diff --git a/QuestPatcher.Core/ExternalFilesDownloader.cs b/QuestPatcher.Core/ExternalFilesDownloader.cs index 6689e75..6f4a414 100644 --- a/QuestPatcher.Core/ExternalFilesDownloader.cs +++ b/QuestPatcher.Core/ExternalFilesDownloader.cs @@ -108,7 +108,8 @@ public string SupportedVersion /// /// Index for file downloads. Used by default, but if it fails QP will fallback to resources /// - private const string DownloadsUrl = "https://beatmods.wgzeyu.com/github/MicroCBer/QuestPatcher/Resources/file-downloads.json"; + private const string DownloadsUrl = "https://raw.githubusercontent.com/MicroCBer/QuestPatcher/main/QuestPatcher.Core/Resources/file-downloads.json"; + private const string DownloadsUrlCn = "https://beatmods.wgzeyu.com/github/MicroCBer/QuestPatcher/Resources/file-downloads.json"; private readonly Dictionary _fileTypes = new() { @@ -326,10 +327,20 @@ private List LoadDownloadSetsFromResources() /// /// The available download sets /// If no download sets were in the pulled file, i.e. it was empty + /// If both url failed private async Task> LoadDownloadSetsFromWeb() { - Log.Debug($"Getting download URLs from {DownloadsUrl} . . ."); - string data = await _webClient.DownloadStringTaskAsync(DownloadsUrl); + string data; + try + { + Log.Debug($"Getting download URLs from {DownloadsUrl} . . ."); + data = await _webClient.DownloadStringTaskAsync(DownloadsUrl); + } + catch(Exception e) + { + Log.Debug($"Getting download URLs from {DownloadsUrlCn} . . ."); + data = await _webClient.DownloadStringTaskAsync(DownloadsUrlCn); + } using StringReader stringReader = new(data); using JsonReader jsonReader = new JsonTextReader(stringReader); diff --git a/QuestPatcher.Core/Patching/PatchingManager.cs b/QuestPatcher.Core/Patching/PatchingManager.cs index ba56655..a1ef27b 100644 --- a/QuestPatcher.Core/Patching/PatchingManager.cs +++ b/QuestPatcher.Core/Patching/PatchingManager.cs @@ -8,15 +8,18 @@ using System.IO.Compression; using System.Linq; using System.Net; +using System.Net.Http; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using AssetsTools.NET; using AssetsTools.NET.Extra; +using Newtonsoft.Json.Linq; using QuestPatcher.Axml; using QuestPatcher.Core.Modding; using Serilog; +using SemVersion = SemanticVersioning.Version; namespace QuestPatcher.Core.Patching { @@ -175,7 +178,7 @@ public async Task LoadInstalledApp() Log.Information("Checking APK modding status . . ."); bool isCracked = false; - await Task.Run(async () => + await Task.Run(() => { using ZipArchive apkArchive = ZipFile.OpenRead(_storedApkPath); @@ -183,40 +186,8 @@ await Task.Run(async () => isModded = apkArchive.GetEntry(QuestPatcherTagName) != null || OtherTagNames.Any(tagName => apkArchive.GetEntry(tagName) != null); is64Bit = apkArchive.GetEntry("lib/arm64-v8a/libil2cpp.so") != null; is32Bit = apkArchive.GetEntry("lib/armeabi-v7a/libil2cpp.so") != null; - /* - var sign = apkArchive.GetEntry("META-INF/BSQUEST.RSA"); - if(sign==null)sign=apkArchive.GetEntry("META-INF/BS.RSA"); - - string signContent = ""; - if(sign!=null)signContent=await new StreamReader(sign.Open()).ReadToEndAsync(); - isCracked = !(signContent.Contains("QPCN0") ||signContent.Contains("Beat Games0"));*/ - isCracked=apkArchive.GetEntry("lib/arm64-v8a/libfrda.so") !=null|| - apkArchive.GetEntry("lib/arm64-v8a/libscript.so") != null; - // Upload APK data and client data. - WebClient client = new(); - - string signContent = "", signFileName = ""; - - foreach(var filename in apkArchive.Entries) - if(filename.FullName.StartsWith("META-INF") && filename.FullName.EndsWith(".RSA")) - { - signContent = await new StreamReader(apkArchive.GetEntry(filename.FullName).Open()).ReadToEndAsync(); - signFileName = filename.FullName; - } - - client.Headers.Add("Content-Type", "text/plain;charset=UTF-8"); - try - { - await client.UploadStringTaskAsync("https://service-i04m59gt-1258625969.cd.apigw.tencentcs.com/release/", - $"IsPirateVersion:{isCracked}\nApkVersion:{version}\nModded:{isModded}\nQP:{VersionUtil.QuestPatcherVersion.ToString()}\n" + - $"SignFileName:{signFileName}\nSignFileContent:{Base64Encode(signContent)}\n\n"); - }catch(Exception ex) - { - Log.Error("Failed to upload patching log!"); - } + isCracked = apkArchive.GetEntry("lib/arm64-v8a/libfrda.so") != null || apkArchive.GetEntry("lib/arm64-v8a/libscript.so") != null; }); - - if(isCracked) { throw new GameIsCrackedException("Game is cracked!"); @@ -226,9 +197,8 @@ await client.UploadStringTaskAsync("https://service-i04m59gt-1258625969.cd.apigw // Version Check try { - var minimumSupportedVersion = new SemanticVersioning.Version("1.16.4"); - var currentInstalledVersion = new SemanticVersioning.Version(version); - if(currentInstalledVersion < minimumSupportedVersion) throw new GameTooOldException("Game is too old!"); + var minimumSupportedVersion = new SemVersion(1,16, 4); + if(SemVersion.TryParse(version, out var curr) && curr < minimumSupportedVersion) throw new GameTooOldException("Game is too old!"); } catch(GameTooOldException) { @@ -263,15 +233,16 @@ public void ResetInstalledApp() private async Task AttemptCopyUnstrippedUnity(string libsPath, ZipArchive apkArchive) { - + var repoRoot = _config.UseMirrorDownload + ? @"https://beatmods.wgzeyu.com/github/QuestUnstrippedUnity" + : @"https://raw.githubusercontent.com/Lauriethefish/QuestUnstrippedUnity/main"; WebClient client = new(); // Only download the index once if (_libUnityIndex == null) { Log.Debug("Downloading libunity index for the first time . . ."); JsonSerializer serializer = new(); - - string data = await client.DownloadStringTaskAsync("https://beatmods.wgzeyu.com/github/QuestUnstrippedUnity/index.json"); + string data = await client.DownloadStringTaskAsync(repoRoot + "/index.json"); using StringReader stringReader = new(data); using JsonReader reader = new JsonTextReader(stringReader); @@ -301,23 +272,9 @@ private async Task AttemptCopyUnstrippedUnity(string libsPath, ZipArchive Log.Information("Unstripped libunity found. Downloading . . ."); using TempFile tempDownloadPath = _specialFolders.GetTempFile(); - { - /* - string str = await client.DownloadStringTaskAsync("https://ganbei-hot-update-1258625969.file.myqcloud.com/questpatcher_mirror/libunity/mirrored_files.txt"); - string source; - if(str.IndexOf($"{correctVersion}.so") >= 0) - { - source = "https://ganbei-hot-update-1258625969.file.myqcloud.com/questpatcher_mirror/libunity/"; - Log.Information("[ MMirror ] Using MicroBlock's mirror"); - } - else source = "https://beatmods.wgzeyu.com/github/QuestUnstrippedUnity/versions/"; - */ - string source = "https://beatmods.wgzeyu.com/github/QuestUnstrippedUnity/versions/"; - - await _filesDownloader.DownloadUrl( - $"{source}{correctVersion}.so", - tempDownloadPath.Path, "libunity.so"); - } + + await _filesDownloader.DownloadUrl($"{repoRoot}/versions/{correctVersion}.so", tempDownloadPath.Path, "libunity.so"); + await apkArchive.AddFileAsync(tempDownloadPath.Path, Path.Combine(libsPath, "libunity.so"), true); return true; @@ -614,33 +571,6 @@ public async Task PatchApp() string libsPath = InstalledApp.Is64Bit ? "lib/arm64-v8a" : "lib/armeabi-v7a"; - - - - // Upload APK data and client data. - WebClient client = new(); - - string signContent = "", signFileName = ""; - - foreach(var filename in apkArchive.Entries) - if(filename.FullName.StartsWith("META-INF") && filename.FullName.EndsWith(".RSA")) - { - signContent = await new StreamReader(apkArchive.GetEntry(filename.FullName).Open()).ReadToEndAsync(); signFileName = filename.FullName; - } - client.Headers.Add("Content-Type", "text/plain;charset=UTF-8"); - try - { - if(InstallApp != null) - await client.UploadStringTaskAsync("https://service-i04m59gt-1258625969.cd.apigw.tencentcs.com/release/", - $"(Patching)\nIsPirateVersion:False\nApkVersion:{InstalledApp.Version}\nModded:{InstalledApp.IsModded}\nQP:{VersionUtil.QuestPatcherVersion.ToString()}\n" + - $"SignFileName:{signFileName}\nSignFileContent:{Base64Encode(signContent)}\n\n"); - - } - catch(Exception ex) - { - Log.Error("Failed to upload patching log!"); - } - if (!InstalledApp.Is64Bit) { Log.Warning("App is 32 bit!"); @@ -676,35 +606,44 @@ await client.UploadStringTaskAsync("https://service-i04m59gt-1258625969.cd.apigw } // 添加中文翻译 - { + if (SemVersion.TryParse(InstalledApp.Version, out var version) && version <= new SemVersion(1, 20, 0)) { string tempDownloadPath = _specialFolders.TempFolder; Log.Information("[ CN Translation ] Adding Chinese translation.."); // 获取翻译文件地址 - WebClient wclient = new WebClient(); - string localization=await wclient.DownloadStringTaskAsync("https://bs.wgzeyu.com/localization/zh-hans.json"); - Newtonsoft.Json.Linq.JObject lca = Newtonsoft.Json.Linq.JObject.Parse(localization); - if(!(((Newtonsoft.Json.Linq.JObject) lca["quest"]).TryGetValue(InstalledApp.Version,out _))) + try { - Log.Warning($"[ CN Translation ] The translation of the version {InstalledApp.Version} doesn't exist."); + using HttpClient httpClient = new HttpClient(); + var res = JObject.Parse(await httpClient.GetStringAsync("https://bs.wgzeyu.com/localization/zh-hans.json")); + var fileUrl = res["quest"]?[InstalledApp.Version]?["fileurl"]?.ToString(); + var fileApkPath = res["quest"]?[InstalledApp.Version]?["filepath"]?.ToString(); + if(fileUrl == null || fileApkPath == null) + { + Log.Warning("[ CN Translation ] No translation for {Version}", InstalledApp.Version); + } + else + { + fileUrl = @"https://bs.wgzeyu.com/localization/" + fileUrl; + // 获取翻译文件 + Log.Information("[ CN Translation ] Downloading translation file: {Url}", fileUrl); + + await _filesDownloader.DownloadUrl(fileUrl, tempDownloadPath, "templanguage_trans.lang"); + Log.Information("[ CN Translation ] Translation file downloaded"); + + // 覆盖语言文件 + Log.Information("[ CN Translation ] Adding the file into APK"); + await apkArchive.AddFileAsync(tempDownloadPath+"/templanguage_trans.lang", fileApkPath,true); + } } - else { - // 获取翻译文件 - Log.Information("[ CN Translation ] Downloading translation file: " + - "https://bs.wgzeyu.com/localization/" + lca["quest"][InstalledApp.Version]["fileurl"].ToString()); - - await _filesDownloader.DownloadUrl( - "https://bs.wgzeyu.com/localization/" + lca["quest"][InstalledApp.Version]["fileurl"].ToString(), - tempDownloadPath + "/templanguage_trans.lang", "templanguage_trans.lang"); ; - Log.Information("[ CN Translation ] Finished downloading translation file."); - - // 覆盖语言文件 - Log.Information("[ CN Translation ] Adding the file into APK"); - await apkArchive.AddFileAsync(tempDownloadPath+"/templanguage_trans.lang", - lca["quest"][InstalledApp.Version]["filepath"].ToString(),true); - + catch(Exception e) + { + Log.Error(e, "Failed to add cn localization file"); } } + else + { + Log.Warning("[ CN Translation ] No translation for {Version}", InstalledApp.Version); + } // Add permissions to the manifest diff --git a/QuestPatcher.Core/QuestPatcherService.cs b/QuestPatcher.Core/QuestPatcherService.cs index 9cb814d..66ab6e8 100644 --- a/QuestPatcher.Core/QuestPatcherService.cs +++ b/QuestPatcher.Core/QuestPatcherService.cs @@ -126,7 +126,6 @@ protected async Task RunStartup() MigrateOldFiles(); CoreModUtils.Instance.PackageId = Config.AppId; - await CoreModUtils.Instance.RefreshCoreMods(); await Task.WhenAll(CoreModUtils.Instance.RefreshCoreMods(), DownloadMirrorUtil.Instance.Refresh()); await PatchingManager.LoadInstalledApp(); await ModManager.LoadModsForCurrentApp(); diff --git a/QuestPatcher.Core/Resources/file-downloads.json b/QuestPatcher.Core/Resources/file-downloads.json index e5d447a..52be3ee 100644 --- a/QuestPatcher.Core/Resources/file-downloads.json +++ b/QuestPatcher.Core/Resources/file-downloads.json @@ -31,5 +31,38 @@ "any": "https://bs.wgzeyu.com/speedlimit/qpfile/OVRPlatformSDK_v1.36.0.zip" } } + }, + { + "supportedVersions": ">=2.2.2", + "downloads": { + "UberApkSigner": { + "any": "https://github.com/patrickfav/uber-apk-signer/releases/download/v1.2.1/uber-apk-signer-1.2.1.jar" + }, + "Modloader64": { + "any": "https://github.com/sc2ad/QuestLoader/releases/download/v1.2.3/libmodloader64.so" + }, + "Main64": { + "any": "https://github.com/sc2ad/QuestLoader/releases/download/v1.2.3/libmain64.so" + }, + "Modloader32": { + "any": "https://github.com/sc2ad/QuestLoader/releases/download/v1.2.3/libmodloader32.so" + }, + "Main32": { + "any": "https://github.com/sc2ad/QuestLoader/releases/download/v1.2.3/libmain32.so" + }, + "PlatformTools": { + "windows": "https://dl.google.com/android/repository/platform-tools-latest-windows.zip", + "mac": "https://dl.google.com/android/repository/platform-tools-latest-darwin.zip", + "linux": "https://dl.google.com/android/repository/platform-tools-latest-linux.zip" + }, + "Jre": { + "windows": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.11%2B9/OpenJDK11U-jre_x64_windows_hotspot_11.0.11_9.zip", + "mac": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.11%2B9/OpenJDK11U-jre_x64_mac_hotspot_11.0.11_9.tar.gz", + "linux": "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.11%2B9/OpenJDK11U-jre_x64_linux_hotspot_11.0.11_9.tar.gz" + }, + "OvrPlatformSdk": { + "any": "https://securecdn.oculus.com/binaries/download/?id=1180710875385946&access_token=OC%7C1196467420370658%7C" + } + } } ] \ No newline at end of file diff --git a/QuestPatcher.Core/Utils/CoreModUtils.cs b/QuestPatcher.Core/Utils/CoreModUtils.cs index 7ea9d6f..007862e 100644 --- a/QuestPatcher.Core/Utils/CoreModUtils.cs +++ b/QuestPatcher.Core/Utils/CoreModUtils.cs @@ -14,7 +14,8 @@ public class CoreModUtils { public static readonly CoreModUtils Instance = new CoreModUtils(); - private const string BeatSaberCoreModsUrl = @"https://beatmods.wgzeyu.com/github/BMBFresources/com.beatgames.beatsaber/core-mods.json"; + private const string BeatSaberCoreModsUrl = @"https://github.com/qe201020335/BMBFResourceMirror/raw/master/com.beatgames.beatsaber/core-mods.json"; + private const string BeatSaberCoreModsCnUrl = @"https://beatmods.wgzeyu.com/github/BMBFresources/com.beatgames.beatsaber/core-mods.json"; public const string BeatSaberPackageID = @"com.beatgames.beatsaber"; private readonly HttpClient _client = new(); private CoreModUtils() @@ -56,14 +57,21 @@ public async Task RefreshCoreMods() { try { - using var res = await _client.GetAsync(BeatSaberCoreModsUrl, _cancellationTokenSource.Token); - res.EnsureSuccessStatusCode(); - _coreMods = JObject.Parse(await res.Content.ReadAsStringAsync()); + var res = await _client.GetStringAsync(BeatSaberCoreModsUrl, _cancellationTokenSource.Token); + _coreMods = JObject.Parse(res); } catch(Exception e) { - Log.Error(e, "Cannot fetch core mods"); - // we don't want to overwrite what we previously have + try + { + var res = await _client.GetStringAsync(BeatSaberCoreModsCnUrl, _cancellationTokenSource.Token); + _coreMods = JObject.Parse(res); + } + catch(Exception exception) + { + Log.Error(exception, "Cannot fetch core mods"); + // we don't want to overwrite what we previously have + } } } else @@ -82,7 +90,7 @@ public List GetCoreMods(string packageVersion) } catch(Exception e) { - Log.Error(e, "Unexpected Error while finding core mods for {}",packageVersion); + Log.Error(e, "Unexpected Error while finding core mods for {Version}",packageVersion); return new List(); } } diff --git a/QuestPatcher.Core/Utils/DownloadMirrorUtil.cs b/QuestPatcher.Core/Utils/DownloadMirrorUtil.cs index a696c8a..07284af 100644 --- a/QuestPatcher.Core/Utils/DownloadMirrorUtil.cs +++ b/QuestPatcher.Core/Utils/DownloadMirrorUtil.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Net.Http; using System.Threading; @@ -10,73 +11,87 @@ namespace QuestPatcher.Core.Utils; public class DownloadMirrorUtil { - public static readonly DownloadMirrorUtil Instance = new (); - + public static readonly DownloadMirrorUtil Instance = new(); + private const string MirrorUrl = @"https://bs.wgzeyu.com/localization/mods.json"; private long _lastRefreshTime = 0; - + private readonly HttpClient _client = new(); - - private readonly Dictionary _mirrorUrls = new (); - private string _coreModPackageId = ""; + + private Dictionary _mirrorUrls = new(); private CancellationTokenSource? _cancellationTokenSource; - + + private readonly Dictionary _staticMirrors = new() + { + // TODO Add Static ones if needed + }; + + public IDictionary StaticMirrors => _staticMirrors; + private DownloadMirrorUtil() { - } public async Task Refresh() { Log.Information("Refreshing download mirror URL "); - + // Cancel a previous refresh attempt in case it is not finished _cancellationTokenSource?.Cancel(); _cancellationTokenSource?.Dispose(); _cancellationTokenSource = new CancellationTokenSource(); - + var token = _cancellationTokenSource.Token; try { - using var res = await _client.GetAsync(MirrorUrl, _cancellationTokenSource.Token); - res.EnsureSuccessStatusCode(); + var res = await _client.GetStringAsync(MirrorUrl, token); - var jObject = JObject.Parse(await res.Content.ReadAsStringAsync()); - _mirrorUrls.Clear(); + var jObject = JObject.Parse(res); + token.ThrowIfCancellationRequested(); - foreach (var pair in jObject) + var mirrorUrls = new Dictionary(_staticMirrors); + + foreach(var pair in jObject) { var mirror = pair.Value?["mirrorUrl"]?.ToString(); - if (mirror != null) + if(mirror != null) { - _mirrorUrls.Add(pair.Key, mirror); + mirrorUrls[pair.Key] = mirror; } } + token.ThrowIfCancellationRequested(); + + _mirrorUrls = mirrorUrls; _lastRefreshTime = DateTimeOffset.Now.ToUnixTimeSeconds(); } + catch(OperationCanceledException) + { + Log.Warning("Refresh mirror url cancelled"); + } catch(Exception e) { - Log.Error(e, "Cannot fetch mirror download url"); + Log.Error(e, "Cannot fetch mirror url"); // we don't want to overwrite what we previously have } } - + public async Task GetMirrorUrl(string original) { - if (DateTimeOffset.Now.ToUnixTimeSeconds() - _lastRefreshTime > 300) + if(DateTimeOffset.Now.ToUnixTimeSeconds() - _lastRefreshTime > 300) { + Log.Information("Mirror Url cache too old! Refreshing"); await Refresh(); } - if (_mirrorUrls.ContainsKey(original)) + if(_mirrorUrls.TryGetValue(original, out var mirror)) { - Log.Information($"Mirror Url found: {_mirrorUrls[original]}"); - return _mirrorUrls[original]; + Log.Debug("Mirror Url found: {Mirror}", mirror); + return mirror; } - Log.Warning($"Mirror Url not found for {original}"); + + Log.Warning("Mirror Url not found for {Original}", original); return original; } - -} \ No newline at end of file +} diff --git a/QuestPatcher/BrowseImportManager.cs b/QuestPatcher/BrowseImportManager.cs index f9c35db..3ab7ff3 100644 --- a/QuestPatcher/BrowseImportManager.cs +++ b/QuestPatcher/BrowseImportManager.cs @@ -513,7 +513,7 @@ private async Task InstallMissingCoreMods(List mods) { } else { - Log.Fatal("Core Mod {} has null download link!", mod["id"]?.ToString()?? "null"); + Log.Fatal("Core Mod {Id} has null download link!", mod["id"]?.ToString()?? "null"); } } client.Dispose(); diff --git a/QuestPatcher/UIPrompter.cs b/QuestPatcher/UIPrompter.cs index a325301..02b2f4d 100644 --- a/QuestPatcher/UIPrompter.cs +++ b/QuestPatcher/UIPrompter.cs @@ -7,8 +7,10 @@ using System; using System.Diagnostics; using System.Net; +using System.Net.Http; using System.Threading.Tasks; using QuestPatcher.Utils; +using Version = SemanticVersioning.Version; namespace QuestPatcher { @@ -35,14 +37,25 @@ public async Task CheckUpdate() { try { - WebClient client = new(); - client.Headers.Add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36"); - client.Headers.Add("accept", "application/json"); - var str = await client.DownloadStringTaskAsync("https://beatmods.wgzeyu.com/githubapi/MicroCBer/QuestPatcher/latest"); - JObject upd = JObject.Parse(str); - - var newest = upd["tag_name"].ToString(); - if (newest != VersionUtil.QuestPatcherVersion.ToString()) + JObject? res = null; + using HttpClient client = new(); + client.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36"); + client.DefaultRequestHeaders.Add("accept", "application/json"); + try + { + res = JObject.Parse(await client.GetStringAsync(@"https://beatmods.wgzeyu.com/githubapi/MicroCBer/QuestPatcher/latest")); + } + catch (Exception e) + { + res = JObject.Parse(await client.GetStringAsync(@"https://api.github.com/repos/MicroCBer/QuestPatcher/releases/latest")); + } + + var newest = res["tag_name"]?.ToString(); + if (newest == null) throw new Exception("Failed to check update."); + + var isLatest = Version.TryParse(newest, out var latest) && latest == VersionUtil.QuestPatcherVersion; + + if (!isLatest) { DialogBuilder builder = new() { @@ -50,7 +63,7 @@ public async Task CheckUpdate() Text = $"**不更新软件,可能会遇到未知问题,强烈建议更新至最新版**\n" + $"同时,非最新版本将不受支持且不保证没有安全问题\n\n" + $"您的版本 - v{VersionUtil.QuestPatcherVersion}\n" + - $"最新版本 - v{newest}", + $"最新版本 - v{latest?.ToString() ?? newest}", HideOkButton = true, HideCancelButton = true }; @@ -81,12 +94,12 @@ public async Task CheckUpdate() } return true; } - catch (WebException ex) + catch (Exception ex) { DialogBuilder builder = new() { - Title = "检查更新失败"+ex.ToString(), - Text = $"请手动检查更新", + Title = "检查更新失败"+ex, + Text = "请手动检查更新", HideOkButton = true }; builder.WithButtons( diff --git a/QuestPatcher/Utils/Util.cs b/QuestPatcher/Utils/Util.cs index e01bc96..35bd882 100644 --- a/QuestPatcher/Utils/Util.cs +++ b/QuestPatcher/Utils/Util.cs @@ -19,7 +19,7 @@ public static void OpenWebpage(string url) } catch (Exception e) { - Log.Error(e, "Failed to open webpage: {}", url); + Log.Error(e, "Failed to open webpage: {Url}", url); } } -} \ No newline at end of file +} diff --git a/VERSION b/VERSION index 2b13e46..6c30cb4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.5.0.1 \ No newline at end of file +2.5.1+cn \ No newline at end of file