feat: parse release note for resource updater (#12092)

* feat: parse release note for resource udpater

* feat: parse release note for resource udpater

* feat: toast 显示版本信息

* style: whitespace for EN

---------

Co-authored-by: uye <99072975+ABA2396@users.noreply.github.com>
Co-authored-by: Constrat <56174894+Constrat@users.noreply.github.com>
This commit is contained in:
MistEO
2025-03-07 17:43:02 +08:00
committed by GitHub
parent c7dd45a8b9
commit 2f10a67d2f
7 changed files with 42 additions and 435 deletions

View File

@@ -13,26 +13,18 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;
using MaaWpfGui.Constants;
using MaaWpfGui.Extensions;
using MaaWpfGui.Helper;
using MaaWpfGui.Main;
using MaaWpfGui.Utilities;
using MaaWpfGui.ViewModels;
using MaaWpfGui.ViewModels.UI;
using MaaWpfGui.ViewModels.UserControl.Settings;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Serilog;
using Stylet;
using static MaaWpfGui.ViewModels.UI.VersionUpdateViewModel;
namespace MaaWpfGui.Models
@@ -41,386 +33,6 @@ namespace MaaWpfGui.Models
{
private static readonly ILogger _logger = Log.ForContext("SourceContext", "ResourceUpdater");
private const string MaaResourceVersion = "resource/version.json";
private const string VersionChecksTemp = MaaResourceVersion + ".checks.tmp";
private static readonly List<string> _maaSingleFiles =
[
"resource/Arknights-Tile-Pos/overview.json",
"resource/stages.json",
"resource/recruitment.json",
"resource/item_index.json",
"resource/battle_data.json",
"resource/infrast.json",
"resource/global/YoStarJP/resource/recruitment.json",
"resource/global/YoStarJP/resource/item_index.json",
"resource/global/YoStarJP/resource/version.json",
"resource/global/YoStarEN/resource/recruitment.json",
"resource/global/YoStarEN/resource/item_index.json",
"resource/global/YoStarEN/resource/version.json",
"resource/global/txwy/resource/recruitment.json",
"resource/global/txwy/resource/item_index.json",
"resource/global/txwy/resource/version.json",
"resource/global/YoStarKR/resource/recruitment.json",
"resource/global/YoStarKR/resource/item_index.json",
"resource/global/YoStarKR/resource/version.json",
];
private const string MaaDynamicFilesIndex = "resource/dynamic_list.txt";
public enum UpdateResult
{
/// <summary>
/// update resource success
/// </summary>
Success,
/// <summary>
/// update resource failed
/// </summary>
Failed,
/// <summary>
/// resource not modified
/// </summary>
NotModified,
}
// 只有 Release 版本才会检查更新
// ReSharper disable once UnusedMember.Global
public static async Task UpdateAndToastAsync()
{
var ret = await UpdateAsync();
string toastMessage = ret switch
{
UpdateResult.Failed => LocalizationHelper.GetString("GameResourceFailed"),
UpdateResult.Success => LocalizationHelper.GetString("GameResourceUpdated"),
_ => string.Empty,
};
if (!string.IsNullOrEmpty(toastMessage))
{
ToastNotification.ShowDirect(toastMessage);
}
}
private static async Task<string> GetResourceApiAsync()
{
string mirror = ConfigurationHelper.GetGlobalValue(ConfigurationKeys.ResourceApi, MaaUrls.MaaResourceApi);
if (mirror != MaaUrls.MaaResourceApi && await IsMirrorAccessibleAsync(mirror))
{
return mirror;
}
var mirrorList = new List<string>
{
MaaUrls.S3ResourceApi,
MaaUrls.R2ResourceApi,
MaaUrls.AnnMirrorResourceApi,
};
while (mirrorList.Count != 0)
{
// random select a mirror
var index = new Random().Next(0, mirrorList.Count);
var mirrorUrl = mirrorList[index];
if (await IsMirrorAccessibleAsync(mirrorUrl))
{
mirror = mirrorUrl;
break;
}
mirrorList.RemoveAt(index);
}
if (mirror != MaaUrls.MaaResourceApi)
{
ConfigurationHelper.SetGlobalValue(ConfigurationKeys.ResourceApi, mirror);
}
return mirror;
}
private static async Task<bool> IsMirrorAccessibleAsync(string mirrorUrl)
{
using var response = await Instances.HttpService.GetAsync(new Uri(mirrorUrl + MaaResourceVersion));
return response is { StatusCode: System.Net.HttpStatusCode.OK };
}
private static async Task<bool> CheckUpdateAsync(string baseUrl)
{
var url = baseUrl + MaaResourceVersion;
using var response = await ETagCache.FetchResponseWithEtag(url);
if (response is not { StatusCode: System.Net.HttpStatusCode.OK })
{
return false;
}
var tmp = Path.Combine(Environment.CurrentDirectory, VersionChecksTemp);
if (!await HttpResponseHelper.SaveResponseToFileAsync(response, tmp))
{
return false;
}
_versionUrl = url;
_versionEtag = response.Headers.ETag?.Tag ?? string.Empty;
ToastNotification.ShowDirect(LocalizationHelper.GetString("GameResourceUpdating"));
return true;
}
private static string _versionUrl = string.Empty;
private static string _versionEtag = string.Empty;
private static void PostProcVersionChecks()
{
var tmp = Path.Combine(Environment.CurrentDirectory, VersionChecksTemp);
var version = Path.Combine(Environment.CurrentDirectory, MaaResourceVersion);
if (File.Exists(tmp))
{
File.Copy(tmp, version, true);
File.Delete(tmp);
}
else
{
return;
}
ETagCache.Set(_versionUrl, _versionEtag);
}
public static async Task<UpdateResult> UpdateAsync()
{
var baseUrl = await GetResourceApiAsync();
bool needUpdate = await CheckUpdateAsync(baseUrl);
if (!needUpdate)
{
return UpdateResult.NotModified;
}
OutputDownloadProgress(1, LocalizationHelper.GetString("GameResourceUpdatePreparing"));
var ret1 = await UpdateFilesWithIndexAsync(baseUrl);
if (ret1 == UpdateResult.Failed)
{
// 模板图片如果没更新成功但是item_index.json更新成功了这种情况会导致
// 下次启动时检查item_index发现对应的文件不存在则会弹窗报错
// 所以如果模板图片没更新成功干脆就不更新item_index.json了
// 地图数据等也是同理
return UpdateResult.Failed;
}
OutputDownloadProgress(2, LocalizationHelper.GetString("GameResourceUpdatePreparing"));
var ret2 = await UpdateSingleFilesAsync(baseUrl);
if (ret2 == UpdateResult.Failed)
{
return UpdateResult.Failed;
}
PostProcVersionChecks();
if (ret1 == UpdateResult.Success || ret2 == UpdateResult.Success)
{
OutputDownloadProgress(LocalizationHelper.GetString("GameResourceUpdated"));
// 现在用的和自动安装服更新包一个逻辑,看看有没有必要分开
if (SettingsViewModel.VersionUpdateSettings.AutoInstallUpdatePackage)
{
await Bootstrapper.RestartAfterIdleAsync();
}
return UpdateResult.Success;
}
OutputDownloadProgress(LocalizationHelper.GetString("GameResourceNotModified"));
return UpdateResult.NotModified;
}
private static async Task<UpdateResult> UpdateSingleFilesAsync(string baseUrl, int maxRetryTime = 2)
{
UpdateResult ret = UpdateResult.NotModified;
var maxCount = _maaSingleFiles.Count;
var count = 0;
// TODO: 加个文件存这些文件的 hash如果 hash 没变就不下载了,只需要请求一次
foreach (var file in _maaSingleFiles)
{
var sRet = await UpdateFileWithETagAsync(baseUrl, file, file, maxRetryTime);
if (sRet == UpdateResult.Failed)
{
OutputDownloadProgress(LocalizationHelper.GetString("GameResourceFailed"));
return UpdateResult.Failed;
}
OutputDownloadProgress(2, ++count, maxCount);
if (ret == UpdateResult.NotModified && sRet == UpdateResult.Success)
{
ret = UpdateResult.Success;
}
}
OutputDownloadProgress(2, "Update completed");
return ret;
}
// 地图文件、掉落材料的图片、基建技能图片
// 这些文件数量不固定,需要先获取索引文件,再根据索引文件下载
private static async Task<UpdateResult> UpdateFilesWithIndexAsync(string baseUrl, int maxRetryTime = 2)
{
var indexSRet = await UpdateFileWithETagAsync(baseUrl, MaaDynamicFilesIndex, MaaDynamicFilesIndex, maxRetryTime);
if (indexSRet == UpdateResult.Failed)
{
return UpdateResult.Failed;
}
var indexPath = Path.Combine(Environment.CurrentDirectory, MaaDynamicFilesIndex);
if (!File.Exists(indexPath))
{
return UpdateResult.Failed;
}
var ret = UpdateResult.NotModified;
var context = await File.ReadAllTextAsync(indexPath);
var maxCount = context
.Split('\n')
.ToList()
.Where(file => !string.IsNullOrEmpty(file))
.Count(file => !File.Exists(Path.Combine(Environment.CurrentDirectory, file)));
var count = 0;
foreach (var file in context.Split('\n').ToList()
.Where(file => !string.IsNullOrEmpty(file))
.Where(file => !File.Exists(Path.Combine(Environment.CurrentDirectory, file))))
{
var sRet = await UpdateFileWithETagAsync(baseUrl, file, file, maxRetryTime);
if (sRet == UpdateResult.Failed)
{
OutputDownloadProgress(LocalizationHelper.GetString("GameResourceFailed"));
return UpdateResult.Failed;
}
OutputDownloadProgress(1, ++count, maxCount);
if (ret == UpdateResult.NotModified && sRet == UpdateResult.Success)
{
ret = UpdateResult.Success;
}
}
OutputDownloadProgress(1, "Update completed");
return ret;
}
private static UpdateResult ResponseToUpdateResult(HttpResponseMessage? response)
{
if (response == null)
{
return UpdateResult.Failed;
}
if (response.StatusCode == System.Net.HttpStatusCode.NotModified)
{
return UpdateResult.NotModified;
}
return response.StatusCode == System.Net.HttpStatusCode.OK
? UpdateResult.Success
: UpdateResult.Failed;
}
private static async Task<UpdateResult> UpdateFileWithETagAsync(string baseUrl, string file, string saveTo, int maxRetryTime = 0)
{
saveTo = Path.Combine(Environment.CurrentDirectory, saveTo);
var encodedFilePath = string.Join('/', file.Split('/').Select(HttpUtility.UrlEncode));
var url = baseUrl + encodedFilePath;
int retryCount = 0;
UpdateResult updateResult;
do
{
using var response = await ETagCache.FetchResponseWithEtag(url, !File.Exists(saveTo));
updateResult = ResponseToUpdateResult(response);
switch (updateResult)
{
case UpdateResult.Success
when !await HttpResponseHelper.SaveResponseToFileAsync(response, saveTo):
return UpdateResult.Failed;
case UpdateResult.Success:
ETagCache.Set(response);
return UpdateResult.Success;
case UpdateResult.NotModified:
return UpdateResult.NotModified;
case UpdateResult.Failed:
default:
await Task.Delay(5000);
break;
}
}
while (retryCount++ < maxRetryTime);
if (updateResult == UpdateResult.Failed)
{
_logger.Warning($"Failed to get file, url: {url}, saveTo: {saveTo}");
}
return updateResult;
}
private static ObservableCollection<LogItemViewModel> _logItemViewModels = [];
private static void OutputDownloadProgress(int index, int count = 0, int maxCount = 1)
{
OutputDownloadProgress(index, $"{count}/{maxCount}({100 * count / maxCount}%)");
}
private static void OutputDownloadProgress(int index, string output)
{
OutputDownloadProgress($"index {index}/2: {output}");
}
private static void OutputDownloadProgress(string output)
{
_logItemViewModels = Instances.TaskQueueViewModel.LogItemViewModels;
if (_logItemViewModels == null)
{
return;
}
var log = new LogItemViewModel(LocalizationHelper.GetString("GameResourceUpdating") + "\n" + output, UiLogColor.Download);
Execute.OnUIThread(() =>
{
if (_logItemViewModels.Count > 0 && _logItemViewModels[0].Color == UiLogColor.Download)
{
if (!string.IsNullOrEmpty(output))
{
_logItemViewModels[0] = log;
}
else
{
_logItemViewModels.RemoveAt(0);
}
}
else if (!string.IsNullOrEmpty(output))
{
_logItemViewModels.Clear();
_logItemViewModels.Add(log);
}
});
}
// 额外加一个从 github 下载完整包的方法,老的版本先留着,看看之后增量还能不能整了
public static async Task<bool> UpdateFromGithubAsync()
{
ToastNotification.ShowDirect(LocalizationHelper.GetString("GameResourceUpdating"));
@@ -493,7 +105,7 @@ namespace MaaWpfGui.Models
/// <item><description><see cref="CheckUpdateRetT.NetworkError"/>:网络错误。</description></item>
/// <item><description><see cref="CheckUpdateRetT.UnknownError"/>:其他错误。</description></item>
/// </list></returns>
public static async Task<(CheckUpdateRetT Ret, string? UpdateUrl)> CheckFromMirrorChyanAsync()
public static async Task<(CheckUpdateRetT Ret, string? UpdateUrl, string? ReleaseNote)> CheckFromMirrorChyanAsync()
{
// https://mirrorc.top/api/resources/MaaResource/latest?current_version=<当前版本日期,从 version.json 里拿时间戳>&cdk=<cdk>&sp_id=<唯一识别码>
// 响应格式为 {"code":0,"msg":"success","data":{"version_name":"2025-01-22 14:28:32.839","version_number":9,"url":"<增量更新网址>"}}
@@ -514,7 +126,7 @@ namespace MaaWpfGui.Models
{
_logger.Error("mirrorc failed");
ToastNotification.ShowDirect(LocalizationHelper.GetString("GameResourceFailed"));
return (CheckUpdateRetT.NetworkError, null);
return (CheckUpdateRetT.NetworkError, null, null);
}
var jsonStr = await response.Content.ReadAsStringAsync();
@@ -532,53 +144,62 @@ namespace MaaWpfGui.Models
if (data is null)
{
ToastNotification.ShowDirect(LocalizationHelper.GetString("GameResourceFailed"));
return (CheckUpdateRetT.UnknownError, null);
return (CheckUpdateRetT.UnknownError, null, null);
}
if (data["code"]?.ToString() != "0")
{
ToastNotification.ShowDirect(data["msg"]?.ToString() ?? LocalizationHelper.GetString("GameResourceFailed"));
return (CheckUpdateRetT.UnknownError, null);
return (CheckUpdateRetT.UnknownError, null, null);
}
if (!DateTime.TryParse(data["data"]?["version_name"]?.ToString(), out var version))
{
ToastNotification.ShowDirect(LocalizationHelper.GetString("GameResourceFailed"));
return (CheckUpdateRetT.UnknownError, null);
return (CheckUpdateRetT.UnknownError, null, null);
}
if (DateTime.Compare(currentVersionDateTime, version) >= 0)
{
return (CheckUpdateRetT.AlreadyLatest, null);
return (CheckUpdateRetT.AlreadyLatest, null, null);
}
// 到这里已经确定有新版本了
_logger.Information($"New version found: {version:yyyy-MM-dd+HH:mm:ss.fff}");
var releaseNote = data["data"]?["release_note"]?.ToString();
_logger.Information($"New version found: {version:yyyy-MM-dd+HH:mm:ss.fff}, {releaseNote}");
releaseNote = LocalizationHelper.CustomCultureInfo.Name.ToLowerInvariant() switch
{
"zh-cn" => $"「{releaseNote}{version:#MMdd}」",
"zh-tw" => $"「{releaseNote}{version:#MMdd}」",
"en-us" => $"「{version:dd/MM} {releaseNote}」",
_ => $"「{version.ToString(LocalizationHelper.CustomCultureInfo.DateTimeFormat.ShortDatePattern.Replace("yyyy", string.Empty).Trim('/', '.'))} {releaseNote}」",
};
if (string.IsNullOrEmpty(cdk))
{
ToastNotification.ShowDirect(LocalizationHelper.GetString("MirrorChyanResourceUpdateTip"));
return (CheckUpdateRetT.OK, null);
ToastNotification.ShowDirect(string.Format(LocalizationHelper.GetString("MirrorChyanResourceUpdateTip"), releaseNote));
return (CheckUpdateRetT.OK, null, releaseNote);
}
var uri = data["data"]?["url"]?.ToString();
if (!string.IsNullOrEmpty(uri))
{
return (CheckUpdateRetT.OK, uri);
return (CheckUpdateRetT.OK, uri, releaseNote);
}
ToastNotification.ShowDirect(LocalizationHelper.GetString("GameResourceFailed"));
return (CheckUpdateRetT.UnknownError, null);
return (CheckUpdateRetT.UnknownError, null, null);
}
public static async Task<bool> DownloadFromMirrorChyanAsync(string? url)
public static async Task<bool> DownloadFromMirrorChyanAsync(string? url, string? releaseNote)
{
if (string.IsNullOrEmpty(url))
{
return false;
}
ToastNotification.ShowDirect(LocalizationHelper.GetString("GameResourceUpdating"));
ToastNotification.ShowDirect(string.Format(LocalizationHelper.GetString("GameResourceUpdatingMirrorChyan"), releaseNote));
bool download = await DownloadFullPackageAsync(url, "MaaResource.zip").ConfigureAwait(false);
if (!download)
{
@@ -628,25 +249,6 @@ namespace MaaWpfGui.Models
return true;
}
public static async Task<bool> UpdateFromMirrorChyanAsync()
{
var (checkRet, uri) = await CheckFromMirrorChyanAsync();
switch (checkRet)
{
case CheckUpdateRetT.AlreadyLatest:
ToastNotification.ShowDirect(LocalizationHelper.GetString("AlreadyLatest"));
return false;
case CheckUpdateRetT.OK:
break;
default:
return false;
}
return await DownloadFromMirrorChyanAsync(uri);
}
/// <summary>
/// 检查并下载资源更新。
/// </summary>
@@ -663,7 +265,7 @@ namespace MaaWpfGui.Models
SettingsViewModel.VersionUpdateSettings.IsCheckingForUpdates = true;
// 可以用 MirrorChyan 资源更新了喵
var (ret, uri) = await CheckFromMirrorChyanAsync();
var (ret, uri, releaseNote) = await CheckFromMirrorChyanAsync();
if (ret != CheckUpdateRetT.OK || string.IsNullOrEmpty(uri))
{
SettingsViewModel.VersionUpdateSettings.IsCheckingForUpdates = false;
@@ -676,7 +278,7 @@ namespace MaaWpfGui.Models
break;
case "MirrorChyan":
if (await DownloadFromMirrorChyanAsync(uri))
if (await DownloadFromMirrorChyanAsync(uri, releaseNote))
{
SettingsViewModel.VersionUpdateSettings.IsCheckingForUpdates = false;
return CheckUpdateRetT.OnlyGameResourceUpdated;

View File

@@ -252,7 +252,7 @@ You can cancel this popup by clicking the Settings - About Us - Issue Reporting
<system:String x:Key="MirrorChyan">MirrorChyan</system:String>
<system:String x:Key="MirrorChyanCdkPlaceholder">Fill after switching source</system:String>
<system:String x:Key="MirrorChyanSoftwareUpdateTip">MirrorChyan has detected a software update. Please go to 「Settings - Software Update」 to configure CDK or using the Global source.</system:String>
<system:String x:Key="MirrorChyanResourceUpdateTip">MirrorChyan has detected a resource update. Please go to 「Settings - Software Update」 to configure CDK, or using the Global source click 「Resource Update」 to update manually.</system:String>
<system:String x:Key="MirrorChyanResourceUpdateTip">MirrorChyan has detected a resource update {0}. Please go to 「Settings - Software Update」 to configure CDK, or using the Global source click 「Resource Update」 to update manually.</system:String>
<system:String x:Key="NewVersionFoundTitle">New Version Found</system:String>
<system:String x:Key="NewVersionFoundDescDownloading">Downloading in the background……</system:String>
<system:String x:Key="NewVersionFoundDescId" xml:space="preserve">Version: </system:String>
@@ -898,6 +898,7 @@ The video aspect ratio needs to be 16:9 without interference factors such as bla
<!-- Api -->
<system:String x:Key="ApiUpdateSuccess">Stage data retrieval successful</system:String>
<system:String x:Key="GameResourceUpdating">Game resources are being updated.</system:String>
<system:String x:Key="GameResourceUpdatingMirrorChyan">MirrorChyan is updating resources{0}.</system:String>
<system:String x:Key="GameResourceUpdatePreparing">Indexing in progress</system:String>
<system:String x:Key="GameResourceNotModified">Game resources updated.</system:String>
<system:String x:Key="GameResourceUpdated">Game resources updated.</system:String>

View File

@@ -252,7 +252,7 @@
<system:String x:Key="MirrorChyan">MirrorChyan</system:String>
<system:String x:Key="MirrorChyanCdkPlaceholder">更新ソース切替後入力</system:String>
<system:String x:Key="MirrorChyanSoftwareUpdateTip">MirrorChyan はソフトウェアの更新を検出しました。CDK を構成するか、グローバル ソースを使用するには、「設定-アップデート設定」に移動してください。</system:String>
<system:String x:Key="MirrorChyanResourceUpdateTip">MirrorChyan はリソースの更新を検出しました。「設定-ソフトウェア更新」に移動して CDK を構成するか、「リソース更新」をクリックして手動で更新してください。</system:String>
<system:String x:Key="MirrorChyanResourceUpdateTip">MirrorChyan はリソースの更新を検出しました{0}。「設定-ソフトウェア更新」に移動して CDK を構成するか、「リソース更新」をクリックして手動で更新してください。</system:String>
<system:String x:Key="NewVersionFoundTitle">新しいバージョンが見つかりました</system:String>
<system:String x:Key="NewVersionFoundDescDownloading">バックグラウンドでダウンロードを行います……</system:String>
<system:String x:Key="NewVersionFoundDescId" xml:space="preserve">バージョン: </system:String>
@@ -901,6 +901,7 @@ C:\\leidian\\LDPlayer9
<!-- Api -->
<system:String x:Key="ApiUpdateSuccess">ステージデータの取得に成功しました</system:String>
<system:String x:Key="GameResourceUpdating">ゲームリソースが更新中です。</system:String>
<system:String x:Key="GameResourceUpdatingMirrorChyan">MirrorChyanがリソースを更新しています{0}。</system:String>
<system:String x:Key="GameResourceUpdatePreparing">索引の作成中</system:String>
<system:String x:Key="GameResourceNotModified">ゲームリソースが更新されました。</system:String>
<system:String x:Key="GameResourceUpdated">ゲームリソースが更新されました。</system:String>

View File

@@ -252,7 +252,7 @@
<system:String x:Key="MirrorChyan">MirrorChyan</system:String>
<system:String x:Key="MirrorChyanCdkPlaceholder">소스 전환 후 입력</system:String>
<system:String x:Key="MirrorChyanSoftwareUpdateTip">MirrorChyan이 소프트웨어 업데이트를 감지했습니다.「설정 - 소프트웨어 업데이트」로 이동하여 CDK를 구성하거나 글로벌 소스를 사용하세요.</system:String>
<system:String x:Key="MirrorChyanResourceUpdateTip">MirrorChyan이 리소스 업데이트를 감지했습니다.「설정 - 소프트웨어 업데이트」로 이동하여 CDK를 구성하거나「리소스 업데이트」를 클릭하여 수동으로 업데이트하세요.</system:String>
<system:String x:Key="MirrorChyanResourceUpdateTip">MirrorChyan이 리소스 업데이트를 감지했습니다{0}.「설정 - 소프트웨어 업데이트」로 이동하여 CDK를 구성하거나「리소스 업데이트」를 클릭하여 수동으로 업데이트하세요.</system:String>
<system:String x:Key="NewVersionFoundTitle">새로운 버전 확인</system:String>
<system:String x:Key="NewVersionFoundDescDownloading">백그라운드에서 다운로드 중……</system:String>
<system:String x:Key="NewVersionFoundDescId" xml:space="preserve">버전: </system:String>
@@ -901,6 +901,7 @@ C:\\leidian\\LDPlayer9
<!-- Api -->
<system:String x:Key="ApiUpdateSuccess">스테이지 데이터 획득 성공</system:String>
<system:String x:Key="GameResourceUpdating">게임 리소스가 업데이트 중입니다.</system:String>
<system:String x:Key="GameResourceUpdatingMirrorChyan">MirrorChyan이 리소스를 업데이트하는 중입니다{0}.</system:String>
<system:String x:Key="GameResourceUpdatePreparing">색인 작성 중</system:String>
<system:String x:Key="GameResourceNotModified">게임 리소스가 업데이트되었습니다.</system:String>
<system:String x:Key="GameResourceUpdated">게임 리소스가 업데이트되었습니다.</system:String>

View File

@@ -249,10 +249,10 @@
<system:String x:Key="UpdateSource">更新源</system:String>
<system:String x:Key="GlobalSource">海外源</system:String>
<system:String x:Key="ForceGithubGlobalSource">强制使用 GitHub</system:String>
<system:String x:Key="MirrorChyan">Mirror 酱</system:String>
<system:String x:Key="MirrorChyan">Mirror酱</system:String>
<system:String x:Key="MirrorChyanCdkPlaceholder">切换更新源后填写</system:String>
<system:String x:Key="MirrorChyanSoftwareUpdateTip">Mirror 酱检测到软件更新。请前往「设置-更新设置」配置 CDK 或使用海外源。</system:String>
<system:String x:Key="MirrorChyanResourceUpdateTip">Mirror 酱检测到资源更新。请前往「设置-更新设置」配置 CDK或使用海外源点击「资源更新」进行手动更新。</system:String>
<system:String x:Key="MirrorChyanSoftwareUpdateTip">Mirror酱检测到软件更新。请前往「设置-更新设置」配置 CDK 或使用海外源。</system:String>
<system:String x:Key="MirrorChyanResourceUpdateTip">Mirror酱检测到资源更新{0}。可前往「设置-更新设置」配置 CDK或使用海外源点击「资源更新」进行手动更新。</system:String>
<system:String x:Key="NewVersionFoundTitle">检测到新版本</system:String>
<system:String x:Key="NewVersionFoundDescDownloading">正在后台下载……</system:String>
<system:String x:Key="NewVersionFoundDescId" xml:space="preserve">版本号: </system:String>
@@ -900,6 +900,7 @@ C:\\leidian\\LDPlayer9。\n
<!-- Api -->
<system:String x:Key="ApiUpdateSuccess">关卡数据获取成功</system:String>
<system:String x:Key="GameResourceUpdating">游戏资源正在更新。</system:String>
<system:String x:Key="GameResourceUpdatingMirrorChyan">Mirror酱正在更新资源{0}。</system:String>
<system:String x:Key="GameResourceUpdatePreparing">正在编制索引</system:String>
<system:String x:Key="GameResourceNotModified">游戏资源已更新。</system:String>
<system:String x:Key="GameResourceUpdated">游戏资源已更新。</system:String>

View File

@@ -249,10 +249,10 @@
<system:String x:Key="UpdateSource">更新來源</system:String>
<system:String x:Key="GlobalSource">全域來源</system:String>
<system:String x:Key="ForceGithubGlobalSource">強制使用 GitHub</system:String>
<system:String x:Key="MirrorChyan">Mirror 醬</system:String>
<system:String x:Key="MirrorChyan">Mirror醬</system:String>
<system:String x:Key="MirrorChyanCdkPlaceholder">切換更新源後填寫</system:String>
<system:String x:Key="MirrorChyanSoftwareUpdateTip">Mirror 醬偵測到軟體更新。請前往「設定-更新設定」設定 CDK 或使用全域來源。</system:String>
<system:String x:Key="MirrorChyanResourceUpdateTip">Mirror 醬偵測到資源更新。請前往「設定-更新設定」設定 CDK或使用全域來源點選「資源更新」進行手動更新。</system:String>
<system:String x:Key="MirrorChyanSoftwareUpdateTip">Mirror醬偵測到軟體更新。請前往「設定-更新設定」設定 CDK 或使用全域來源。</system:String>
<system:String x:Key="MirrorChyanResourceUpdateTip">Mirror醬偵測到資源更新{0}。請前往「設定-更新設定」設定 CDK或使用全域來源點選「資源更新」進行手動更新。</system:String>
<system:String x:Key="NewVersionFoundTitle">檢測到新版本</system:String>
<system:String x:Key="NewVersionFoundDescDownloading">正在後臺下載……</system:String>
<system:String x:Key="NewVersionFoundDescId" xml:space="preserve">版本號: </system:String>
@@ -900,6 +900,7 @@ C:\\leidian\\LDPlayer9。\n
<!-- Api -->
<system:String x:Key="ApiUpdateSuccess">關卡數據獲取成功</system:String>
<system:String x:Key="GameResourceUpdating">遊戲資源正在更新。</system:String>
<system:String x:Key="GameResourceUpdatingMirrorChyan">Mirror醬正在更新資源{0}。</system:String>
<system:String x:Key="GameResourceUpdatePreparing">正在編製索引</system:String>
<system:String x:Key="GameResourceNotModified">遊戲資源已更新。</system:String>
<system:String x:Key="GameResourceUpdated">遊戲資源已更新。</system:String>

View File

@@ -20,11 +20,9 @@ using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows;
using MaaWpfGui.Constants;
using MaaWpfGui.Extensions;
using MaaWpfGui.Helper;
using MaaWpfGui.Main;
using MaaWpfGui.Models;
using MaaWpfGui.Properties;
using MaaWpfGui.Services;
@@ -392,6 +390,7 @@ public class VersionUpdateSettingsUserControlModel : PropertyChangedBase
/// Updates manually.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
/// ReSharper disable once UnusedMember.Global
public async Task ManualUpdate()
{
var ret = await Instances.VersionUpdateViewModel.CheckAndDownloadVersionUpdate();
@@ -422,11 +421,12 @@ public class VersionUpdateSettingsUserControlModel : PropertyChangedBase
}
}
// ReSharper disable once UnusedMember.Global
public async Task ManualUpdateResource()
{
IsCheckingForUpdates = true;
var (ret, uri) = await ResourceUpdater.CheckFromMirrorChyanAsync();
var (ret, uri, releaseNote) = await ResourceUpdater.CheckFromMirrorChyanAsync();
var toastMessage = ret switch
{
VersionUpdateViewModel.CheckUpdateRetT.NoNeedToUpdate => string.Empty,
@@ -456,7 +456,7 @@ public class VersionUpdateSettingsUserControlModel : PropertyChangedBase
bool success = UpdateSource switch
{
"Github" => await ResourceUpdater.UpdateFromGithubAsync(),
"MirrorChyan" => (ret == VersionUpdateViewModel.CheckUpdateRetT.OK) && await ResourceUpdater.DownloadFromMirrorChyanAsync(uri),
"MirrorChyan" => (ret == VersionUpdateViewModel.CheckUpdateRetT.OK) && await ResourceUpdater.DownloadFromMirrorChyanAsync(uri, releaseNote),
_ => await ResourceUpdater.UpdateFromGithubAsync(),
};