feat: 接入Mirror酱

This commit is contained in:
知一一 2025-06-08 23:56:44 +08:00
parent df43422613
commit 7f40cd7c1b
1 changed files with 467 additions and 87 deletions

View File

@ -107,6 +107,7 @@ global g_settings := Map(
;其他
"AutoCheckUpdate", 0, ;自动检查更新
"isPreRelease", 1, ;启用预发布通道
"MirrorUpdate", 0, ;使用Mirror酱检查和更新
"AdjustSize", 0, ;启用画面缩放
"SelfClosing", 0, ;完成后自动关闭程序
"OpenBlablalink", 1, ;完成后打开Blablalink
@ -115,7 +116,8 @@ global g_settings := Map(
global g_numeric_settings := Map(
"SleepTime", 1000, ;默认等待时间
"InterceptionBoss", 1, ;拦截战BOSS选择
"Tolerance", 1 ;宽容度
"Tolerance", 1, ;宽容度
"MirrorCDK", "" ;Mirror酱的CDK
)
;tag 其他全局变量
global Victory := 0
@ -131,12 +133,11 @@ try {
catch {
WriteSettings()
}
if g_settings["AutoCheckUpdate"] {
CheckForUpdateHandler(false) ;调用核心函数,标记为非手动检查
}
if g_settings["AutoCheckUpdate"]
CheckForUpdate(false)
;endregion 读取设置
;region 创建gui
doroGui := Gui("+Resize", "Doro小帮手" currentVersion)
doroGui := Gui("+Resize", "DoroHelper - " currentVersion)
doroGui.Tips := GuiCtrlTips(doroGui) ; 为 doroGui 实例化 GuiCtrlTips
doroGui.Tips.SetBkColor(0xFFFFFF)
doroGui.Tips.SetTxColor(0x000000)
@ -166,6 +167,13 @@ Tab.UseTab("设置")
cbAutoCheckUpdate := AddCheckboxSetting(doroGui, "AutoCheckUpdate", "自动检查更新", "Section R1.2")
doroGui.Tips.SetTip(cbAutoCheckUpdate, "勾选后DoroHelper 启动时会自动连接到 Github 检查是否有新版本")
AddCheckboxSetting(doroGui, "isPreRelease", "测试版渠道", "x+5 R1.2")
MirrorChyan := AddCheckboxSetting(doroGui, "MirrorUpdate", "改用Mirror酱", "R1.2 xs+15")
doroGui.Tips.SetTip(MirrorChyan, "Mirror酱是一个第三方应用分发平台让你能在普通网络环境下更新应用`r`n网址https://mirrorchyan.com/zh/(付费使用)")
MirrorEditControl := doroGui.Add("Edit", "x+5 yp w145 h20")
doroGui.Tips.SetTip(MirrorEditControl, "输入你的Mirror酱CDK")
MirrorEditControl.Value := g_numeric_settings["MirrorCDK"]
MirrorEditControl.OnEvent("Change", (Ctrl, Info) => g_numeric_settings["MirrorCDK"] := Ctrl.Value)
cbAdjustSize := AddCheckboxSetting(doroGui, "AdjustSize", "启用窗口调整", "xs R1.2")
doroGui.Tips.SetTip(cbAdjustSize, "勾选后DoroHelper运行前会尝试将窗口调整至合适的尺寸并在运行结束后还原")
cbOpenBlablalink := AddCheckboxSetting(doroGui, "OpenBlablalink", "任务完成后自动打开Blablalink", "R1.2")
doroGui.Tips.SetTip(cbOpenBlablalink, "勾选后,当 DoroHelper 完成所有已选任务后,会自动在您的默认浏览器中打开 Blablalink 网站")
@ -507,108 +515,480 @@ Initialization() {
AddLog("不足1080p分辨率")
}
}
; if GameRatio != 1.778 {
; MsgBox ("请将游戏画面比例调整至16:9")
; }
}
;endregion 初始化
;region 软件更新
;tag 检查更新
CheckForUpdateHandler(isManualCheck) {
global currentVersion, usr, repo, latestObj ;确保能访问全局变量
try {
allReleases := Github.historicReleases(usr, repo) ; 获取所有版本
if !IsObject(allReleases) || !allReleases.Length {
;tag 统一检查更新
CheckForUpdate(isManualCheck) {
; 全局变量声明 - 确保这些在函数外部有定义
global currentVersion, usr, repo, latestObj, g_settings, g_numeric_settings
latestObj := Map( ; 初始化 latestObj Map
"version", "",
"change_notes", "无更新说明。",
"download_url", "",
"source", "",
"display_name", ""
)
local foundNewVersion := false
local sourceName := ""
local channelInfo := g_settings["isPreRelease"] ? "预发布" : "稳定"
; ==================== Mirror酱 更新检查 ====================
if g_settings["MirrorUpdate"] {
latestObj.source := "mirror"
latestObj.display_name := "Mirror酱"
sourceName := "Mirror酱"
AddLog(sourceName . " 更新检查:开始 (" . channelInfo . " 渠道)...")
if Trim(g_numeric_settings["MirrorCDK"]) = "" {
if (isManualCheck) {
MsgBox("无法获取版本列表,请检查网络或仓库信息。", "检查更新错误", "IconX")
MsgBox("Mirror酱 CDK 为空,无法检查更新。", sourceName . "检查更新错误", "IconX")
}
AddLog(sourceName . " 更新检查CDK为空。")
return
}
targetRelease := "" ; 用于存储我们最终选择的版本对象
local apiUrl := "https://mirrorchyan.com/api/resources/DoroHelper/latest?"
apiUrl .= "cdk=" . g_numeric_settings["MirrorCDK"]
if g_settings["isPreRelease"] {
; 用户希望接收预发布版本,直接取最新的(通常是列表的第一个)
targetRelease := allReleases[1]
AddLog("检查更新:当前设置为预发布版优先,最新版本为 " . targetRelease.version)
} else {
; 用户希望接收稳定版本,遍历查找最新的稳定版
AddLog("检查更新:当前设置为稳定版优先,正在查找...")
for release in allReleases {
; 简单的预发布版判断如果版本名不包含beta, alpha, rc等
if !(InStr(release.version, "beta") || InStr(release.version, "alpha") || InStr(release.version, "rc")) {
targetRelease := release
AddLog("找到最新稳定版:" . targetRelease.version)
break ; 找到最新的稳定版后即停止
}
apiUrl .= "&channel=beta"
}
local HttpRequest := ""
local ResponseStatus := 0
local ResponseBody := "" ; 用于存储原始字节流
try {
HttpRequest := ComObject("WinHttp.WinHttpRequest.5.1")
HttpRequest.Open("GET", apiUrl, false)
HttpRequest.SetRequestHeader("User-Agent", "DoroHelper-AHK-Script/" . currentVersion)
HttpRequest.Send()
ResponseStatus := HttpRequest.Status
if (ResponseStatus = 200) { ; 仅当成功时获取 ResponseBody
ResponseBody := HttpRequest.ResponseBody
}
if !IsObject(targetRelease) { ; 如果遍历后没有找到合适的稳定版
if (isManualCheck) {
MsgBox("未找到合适的稳定版本。", "检查更新")
} catch as e {
if (isManualCheck) {
MsgBox(sourceName . " API 请求失败: " . e.Message, sourceName . "检查更新错误", "IconX")
}
AddLog(sourceName . " API 请求失败: " . e.Message)
return
}
local ResponseTextForJson := "" ; 用于 JSON 解析的文本
if (ResponseStatus = 200) {
if (IsObject(ResponseBody) && (ComObjType(ResponseBody) & 0x2000)) { ; 检查是否为 SafeArray (VT_ARRAY)
try {
local dataPtr := 0
local lBound := 0
local uBound := 0
DllCall("OleAut32\SafeArrayGetLBound", "Ptr", ComObjValue(ResponseBody), "UInt", 1, "Int64*", &lBound)
DllCall("OleAut32\SafeArrayGetUBound", "Ptr", ComObjValue(ResponseBody), "UInt", 1, "Int64*", &uBound)
local actualSize := uBound - lBound + 1
if (actualSize > 0) {
DllCall("OleAut32\SafeArrayAccessData", "Ptr", ComObjValue(ResponseBody), "Ptr*", &dataPtr)
ResponseTextForJson := StrGet(dataPtr, actualSize, "UTF-8")
DllCall("OleAut32\SafeArrayUnaccessData", "Ptr", ComObjValue(ResponseBody))
AddLog(sourceName . " DEBUG: ResponseBody (SafeArray) converted to UTF-8 string using StrGet.")
} else {
AddLog(sourceName . " 警告: SafeArray 大小为0或无效。")
ResponseTextForJson := "" ; 确保 ResponseTextForJson 有定义
}
} catch as e_sa {
AddLog(sourceName . " 错误: 处理 ResponseBody (SafeArray) 失败: " . e_sa.Message ". 类型: " . ComObjType(ResponseBody, "Name"))
ResponseTextForJson := HttpRequest.ResponseText ; 回退
AddLog(sourceName . " 警告: SafeArray 处理失败,回退到 HttpRequest.ResponseText可能存在编码问题。")
}
AddLog("未找到合适的稳定版本。")
} else if (IsObject(ResponseBody)) {
AddLog(sourceName . " 警告: ResponseBody 是对象但不是 SafeArray (类型: " . ComObjType(ResponseBody, "Name") . "),尝试 ADODB.Stream。")
try {
local Stream := ComObject("ADODB.Stream")
Stream.Type := 1 ; adTypeBinary
Stream.Open()
Stream.Write(ResponseBody)
Stream.Position := 0
Stream.Type := 2 ; adTypeText
Stream.Charset := "utf-8"
ResponseTextForJson := Stream.ReadText()
Stream.Close()
AddLog(sourceName . " DEBUG: ResponseBody (non-SafeArray COM Object) converted to UTF-8 string using ADODB.Stream.")
} catch as e_adodb {
AddLog(sourceName . " 错误: ADODB.Stream 处理 ResponseBody (non-SafeArray COM Object) 失败: " . e_adodb.Message)
ResponseTextForJson := HttpRequest.ResponseText ; 最终回退
AddLog(sourceName . " 警告: ADODB.Stream 失败,回退到 HttpRequest.ResponseText可能存在编码问题。")
}
} else {
AddLog(sourceName . " 警告: ResponseBody 不是 COM 对象,或请求未成功。将直接使用 HttpRequest.ResponseText。")
ResponseTextForJson := HttpRequest.ResponseText
}
AddLog(sourceName . " API Response Status 200. Decoded ResponseTextForJson (first 500 chars): " . SubStr(ResponseTextForJson, 1, 500))
try {
local JsonData := Json.Load(&ResponseTextForJson)
if (!IsObject(JsonData)) {
if (isManualCheck) MsgBox(sourceName . " API 响应格式错误。", sourceName . "检查更新错误", "IconX")
AddLog(sourceName . " API 响应未能解析为JSON. ResponseText (first 200): " . SubStr(ResponseTextForJson, 1, 200))
return
}
local jsonDataCode := JsonData.Get("code", -1)
local potentialData := JsonData.Get("data", unset)
if (jsonDataCode != 0) {
local errorMsg := sourceName . " API 返回错误。 Code: " . jsonDataCode . "."
if (JsonData.Has("msg") && Trim(JsonData.msg) != "") {
errorMsg .= " 消息: " . JsonData.msg
} else {
errorMsg .= " (API未提供详细错误消息)"
}
if (isManualCheck) {
MsgBox(errorMsg, sourceName . "检查更新错误", "IconX")
}
AddLog(errorMsg)
return
}
if (!IsSet(potentialData) || !IsObject(potentialData)) {
local errorMsg := sourceName . " API 响应成功 (code 0),但 'data' 字段缺失或非对象类型。"
if (JsonData.Has("msg") && Trim(JsonData.msg) != "") {
errorMsg .= " API 消息: " . JsonData.msg
}
if (isManualCheck) {
MsgBox(errorMsg, sourceName . "检查更新错误", "IconX")
}
AddLog(errorMsg . " Type of 'data' retrieved: " . Type(potentialData))
return
}
local mirrorData := potentialData
latestObj.version := mirrorData.Get("version_name", "")
latestObj.change_notes := mirrorData.Get("release_note", "无更新说明。")
latestObj.download_url := mirrorData.Get("url", "")
if latestObj.version = "" {
if (isManualCheck) {
MsgBox(sourceName . " API 响应中版本信息为空。", sourceName . "检查更新错误", "IconX")
}
AddLog(sourceName . " 更新检查API响应中版本信息为空。")
return
}
AddLog(sourceName . " 更新检查:获取到版本 " . latestObj.version)
if (CompareVersionsSemVer(latestObj.version, currentVersion) > 0) {
foundNewVersion := true
AddLog(sourceName . " 版本比较:发现新版本。")
} else {
AddLog(sourceName . " 版本比较:当前已是最新或更新。")
}
} catch as e {
local errorDetails := "错误类型: " . Type(e) . ", 消息: " . e.Message
if e.HasProp("What") errorDetails .= "`n触发对象/操作: " . e.What
if e.HasProp("File") errorDetails .= "`n文件: " . e.File
if e.HasProp("Line") errorDetails .= "`n行号: " . e.Line
if (isManualCheck) MsgBox("处理 " . sourceName . " JSON 数据时发生内部错误: `n" . errorDetails, sourceName . "检查更新错误", "IconX")
AddLog(sourceName . " 更新检查处理JSON时发生内部错误: " . errorDetails)
AddLog(sourceName . " 相关的 ResponseTextForJson (前1000字符): " . SubStr(ResponseTextForJson, 1, 1000))
return
}
}
latestObj := targetRelease ; 将选定的版本赋给 latestObj 供后续使用
if (currentVersion != latestObj.version) {
MyGui := Gui("+Resize", "更新提示")
MyGui.Add("Text", "w300 xm ym", "DoroHelper存在更新版本 (" . (g_settings["isPreRelease"] ? "预发布" : "稳定") . "):") ; 提示版本类型
MyGui.Add("Text", "xp yp+20 w300", "版本号: " . latestObj.version)
MyGui.Add("Text", "xp yp+20 w300", "更新内容:")
MyEdit := MyGui.Add("Edit", "w250 h200 ReadOnly VScroll Border", latestObj.change_notes)
MyGui.Add("Text", "xp yp+210 w300", "`n是否下载?")
userresponse := ""
MyGui.Add("Button", "xm w100", "").OnEvent("Click", DownloadHandler)
MyGui.Add("Button", "x+10 w100", "").OnEvent("Click", (*) => MyGui.Destroy())
MyGui.Show("w300 h350 Center ")
}
else {
;没有新版本
if (isManualCheck) { ;只有手动检查时才提示
MsgBox("当前Doro (" . (g_settings["isPreRelease"] ? "预发布通道" : "稳定版通道") . ")已是最新版本: " . currentVersion, "检查更新")
} else { ; ResponseStatus != 200
local errorResponseText := HttpRequest.ResponseText ; 尝试获取错误响应文本
local responseTextPreview := SubStr(errorResponseText, 1, 300)
if (isManualCheck) {
MsgBox(sourceName . " API 请求失败!`n状态码: " . ResponseStatus . "`n响应预览:`n" . responseTextPreview, sourceName . " API 错误", "IconX")
}
}
}
catch as githubError {
;只有手动检查时才提示连接错误,自动检查时静默失败
if (isManualCheck) {
MsgBox("检查更新失败无法连接到Github或仓库信息错误`n(" githubError.Message ")", "检查更新错误", "IconX")
}
AddLog("检查更新失败: " . githubError.Message)
}
}
;tag 专用下载处理函数
DownloadHandler(*) {
try {
downloadTempName := "DoroDownload.exe"
finalName := "DoroHelper-" latestObj.version ".exe"
local downloadUrlToUse := ""
if IsObject(latestObj.downloadURLs) && latestObj.downloadURLs.Length > 0 {
downloadUrlToUse := latestObj.downloadURLs[1]
} else if IsObject(latestObj.downloadURL) { ; 兼容 historicReleases 返回的单个 downloadURL
downloadUrlToUse := latestObj.downloadURL
} else {
MsgBox("错误:找不到有效的下载链接。", "下载错误", "IconX")
AddLog(sourceName . " API 请求失败!状态码: " . ResponseStatus . ", 响应预览: " . responseTextPreview)
return
}
; ==================== Github 更新检查 (如果 MirrorUpdate 未启用) ====================
} else {
latestObj.source := "github"
latestObj.display_name := "Github"
sourceName := "Github"
AddLog(sourceName . " 更新检查:开始 (" . channelInfo . " 渠道)...")
try {
local allReleases := Github.historicReleases(usr, repo) ; 获取所有版本
if !(allReleases is Array) || !allReleases.Length { ; AHK v2: is Array
if (isManualCheck) {
MsgBox("无法获取 Github 版本列表,请检查网络或仓库信息。", sourceName . "检查更新错误", "IconX")
}
AddLog(sourceName . " 更新检查:无法获取版本列表。")
return
}
local targetRelease := ""
if g_settings["isPreRelease"] {
targetRelease := allReleases[1]
if !(IsObject(targetRelease) && (targetRelease.HasProp("version") || targetRelease.HasProp("tag_name"))) {
local errMsg := sourceName . " 更新检查:获取到的最新预发布 Release 对象无效或缺少版本信息。"
if (isManualCheck) MsgBox(errMsg, sourceName . "检查更新错误", "IconX")
AddLog(errMsg)
return
}
AddLog(sourceName . " 更新检查:预发布版优先,已选定 Release。")
} else {
AddLog(sourceName . " 更新检查:稳定版优先,正在查找...")
for release_item in allReleases {
if !(IsObject(release_item) && (release_item.HasProp("version") || release_item.HasProp("tag_name"))) {
AddLog(sourceName . " DEBUG: 跳过一个无效的或缺少版本信息的 Release 对象。")
continue
}
local current_release_version := release_item.HasProp("version") ? release_item.version : release_item.tag_name
if !(InStr(current_release_version, "beta") || InStr(current_release_version, "alpha") || InStr(current_release_version, "rc")) {
targetRelease := release_item
AddLog(sourceName . " 更新检查:找到稳定版 " . current_release_version)
break
}
}
if !IsObject(targetRelease) {
AddLog(sourceName . " 更新检查:未找到稳定版,将使用最新版本进行比较。")
targetRelease := allReleases[1]
if !(IsObject(targetRelease) && (targetRelease.HasProp("version") || targetRelease.HasProp("tag_name"))) {
local errMsg := sourceName . " 更新检查:回退到的最新 Release 对象也无效或缺少版本信息。"
if (isManualCheck) MsgBox(errMsg, sourceName . "检查更新错误", "IconX")
AddLog(errMsg)
return
}
}
}
if !IsObject(targetRelease) {
local errMsg := sourceName . " 更新检查:最终未能确定有效的 targetRelease 对象。"
if (isManualCheck) MsgBox(errMsg, sourceName . "检查更新错误", "IconX")
AddLog(errMsg)
return
}
; 版本号
if (targetRelease.HasProp("version")) {
latestObj.version := targetRelease.version
} else if (targetRelease.HasProp("tag_name")) {
latestObj.version := targetRelease.tag_name
} else {
latestObj.version := ""
AddLog(sourceName . " 警告: Release 对象缺少 'version' 或 'tag_name' 属性。")
}
; 更新内容
if (targetRelease.HasProp("change_notes")) {
latestObj.change_notes := targetRelease.change_notes
} else if (targetRelease.HasProp("body")) {
latestObj.change_notes := targetRelease.body
} else {
latestObj.change_notes := "无更新说明。"
}
if Trim(latestObj.change_notes) = "" {
latestObj.change_notes := "无更新说明。"
}
; 下载链接
latestObj.download_url := "" ; 初始化
if (targetRelease.HasProp("downloadURL") && Trim(targetRelease.downloadURL) != "") {
latestObj.download_url := targetRelease.downloadURL
AddLog(sourceName . " 找到下载链接 (from downloadURL): " . latestObj.download_url)
}
else if (targetRelease.HasProp("assets") && targetRelease.assets is Array && targetRelease.assets.Length > 0) { ; AHK v2: is Array
AddLog(sourceName . " DEBUG: (Fallback) 'downloadURL' not found. Checking 'assets'.")
for asset in targetRelease.assets {
if IsObject(asset) && asset.HasProp("name") && asset.HasProp("browser_download_url") {
AddLog(sourceName . " DEBUG: Checking asset: " . asset.name)
if (InStr(asset.name, "DoroHelper") && InStr(asset.name, ".exe")) {
latestObj.download_url := asset.browser_download_url
AddLog(sourceName . " 找到 .exe asset 下载链接 (from assets): " . latestObj.download_url)
break
}
}
}
if (latestObj.download_url = "")
AddLog(sourceName . " 警告: 在 'assets' 中未精确匹配到 'DoroHelper*.exe' 或 'assets' 结构不符。")
}
else if (targetRelease.HasProp("downloadURLs") && targetRelease.downloadURLs is Array && targetRelease.downloadURLs.Length > 0 && Trim(targetRelease.downloadURLs[1]) != "") { ; AHK v2: is Array
latestObj.download_url := targetRelease.downloadURLs[1]
AddLog(sourceName . " 使用 downloadURLs[1] 作为下载链接 (Fallback): " . latestObj.download_url)
}
else if (targetRelease.HasProp("download_url") && Trim(targetRelease.download_url) != "") {
latestObj.download_url := targetRelease.download_url
AddLog(sourceName . " 使用顶层 download_url 属性作为下载链接 (Fallback): " . latestObj.download_url)
}
else {
AddLog(sourceName . " 警告: Release 对象未找到任何有效的下载链接属性 (已尝试: downloadURL, assets, downloadURLs, download_url)。")
}
if latestObj.version = "" {
local errMsg := sourceName . " 更新检查:未能从选定的 Release 对象获取版本号。"
if (isManualCheck) MsgBox(errMsg, sourceName . "检查更新错误", "IconX")
AddLog(errMsg)
return
}
if latestObj.download_url = "" {
AddLog(sourceName . " 警告: 未能为版本 " . latestObj.version . " 找到有效的下载链接。")
}
AddLog(sourceName . " 更新检查:获取到版本 " . latestObj.version . (latestObj.download_url ? "" : " (下载链接未找到)"))
if (CompareVersionsSemVer(latestObj.version, currentVersion) > 0) {
foundNewVersion := true
AddLog(sourceName . " 版本比较:发现新版本。")
} else {
AddLog(sourceName . " 版本比较:当前已是最新或更新。")
}
} catch as githubError {
if (isManualCheck) {
MsgBox("Github 检查更新失败: `n" . githubError.Message . (githubError.HasProp("Extra") ? "`nExtra: " . githubError.Extra : ""), sourceName . "检查更新错误", "IconX")
}
AddLog(sourceName . " 检查更新失败: " . githubError.Message . (githubError.HasProp("Extra") ? ". Extra: " . githubError.Extra : ""))
return
}
Github.Download(downloadUrlToUse, A_ScriptDir "\" downloadTempName)
FileMove(A_ScriptDir "\" downloadTempName, A_ScriptDir "\" finalName, 1)
MsgBox("新版本已下载至当前目录: " finalName, "下载完成")
ExitApp
}
catch as downloadError {
MsgBox("下载失败,请检查网络`n(" downloadError.Message ")", "下载错误", "IconX")
if FileExist(A_ScriptDir "\" downloadTempName)
FileDelete(A_ScriptDir "\" downloadTempName)
; ==================== 处理检查结果 ====================
if foundNewVersion {
AddLog(sourceName . " 更新检查:发现新版本 " . latestObj.version . ",准备提示用户。")
if (latestObj.download_url = "" && isManualCheck) {
MsgBox("已检测到新版本 " . latestObj.version . ",但未能获取到下载链接。请检查 Github 库或手动下载。", "更新提示", "IconW")
}
local MyGui := Gui("+Resize", "更新提示 (" . latestObj.display_name . ")")
MyGui.SetFont("s10", "Microsoft YaHei UI")
MyGui.Add("Text", "w300 xm ym", "发现 DoroHelper 新版本 (" . channelInfo . " - " . latestObj.display_name . "):")
MyGui.Add("Text", "xp+10 yp+25 w300", "最新版本: " . latestObj.version)
MyGui.Add("Text", "xp yp+20 w300", "当前版本: " . currentVersion)
MyGui.Add("Text", "xp yp+25 w300", "更新内容:")
local notes_for_edit := latestObj.change_notes
notes_for_edit := StrReplace(notes_for_edit, "`r`n", "`n") ; 先统一为 \n
notes_for_edit := StrReplace(notes_for_edit, "`r", "`n") ; \r 也统一为 \n
notes_for_edit := StrReplace(notes_for_edit, "`n", "`r`n") ; 再统一为 Edit 控件的 \r\n
MyGui.Add("Edit", "w250 h200 ReadOnly VScroll Border", notes_for_edit)
MyGui.Add("Button", "xm+20 w100 h30 yp+220", "立即下载").OnEvent("Click", DownloadUpdate)
MyGui.Add("Button", "x+20 w100 h30", "稍后提醒").OnEvent("Click", (*) => MyGui.Destroy())
MyGui.Show("w320 h400 Center")
} else if latestObj.version != "" {
AddLog(sourceName . " 更新检查:当前已是最新版本 " . currentVersion)
if (isManualCheck) {
MsgBox("当前通道为:" . channelInfo . "通道 - " . latestObj.display_name . "`n最新版本为:" . latestObj.version "`n当前版本为:" . currentVersion "`n当前已是最新版本", "检查更新", "IconI")
}
} else {
AddLog((sourceName ? sourceName : "更新") . " 更新检查:未能获取到有效的版本信息或检查被中止。")
if (isManualCheck) {
MsgBox("未能完成更新检查。请查看日志了解详情。", "检查更新", "IconX")
}
}
}
;tag 统一更新下载
DownloadUpdate(*) {
global latestObj
if !IsObject(latestObj) || !latestObj.Has("source") || latestObj.source = "" || !latestObj.Has("version") || latestObj.version = "" {
MsgBox("下载错误:更新信息不完整,无法开始下载。", "下载错误", "IconX")
AddLog("下载错误latestObj 信息不完整。 Source: " . latestObj.Get("source", "N/A") . ", Version: " . latestObj.Get("version", "N/A"))
return
}
downloadTempName := "DoroDownload.exe"
finalName := "DoroHelper-" latestObj.version ".exe"
downloadUrlToUse := latestObj.download_url
if downloadUrlToUse = "" {
MsgBox("错误:找不到有效的 " . latestObj.display_name . " 下载链接。", "下载错误", "IconX")
AddLog(latestObj.display_name . " 下载错误:下载链接为空。")
return
}
AddLog(latestObj.display_name . " 下载:开始下载 " . downloadUrlToUse . "" . A_ScriptDir "\" finalName)
local downloadStatusCode := 0 ; 用于存储下载结果
try {
if latestObj.source == "github" {
ErrorLevel := 0
Github.Download(downloadUrlToUse, A_ScriptDir "\" downloadTempName)
downloadStatusCode := ErrorLevel
if downloadStatusCode != 0 {
throw Error("Github 下载失败 (ErrorLevel: " . downloadStatusCode . "). 检查 Github.Download 库的内部提示或网络。")
}
} else if latestObj.source == "mirror" {
ErrorLevel := 0
Download downloadUrlToUse, A_ScriptDir "\" downloadTempName
downloadStatusCode := ErrorLevel
if downloadStatusCode != 0 {
throw Error("Mirror酱下载失败 (错误代码: " . downloadStatusCode . ")")
}
} else {
throw Error("未知的下载源: " . latestObj.source)
}
FileMove A_ScriptDir "\" downloadTempName, A_ScriptDir "\" finalName, 1
MsgBox("新版本已通过 " . latestObj.display_name . " 下载至当前目录: `n" . A_ScriptDir "\" finalName, "下载完成")
AddLog(latestObj.display_name . " 下载:成功下载并保存为 " . finalName)
ExitApp
} catch as downloadError {
MsgBox(latestObj.display_name . " 下载失败: `n" . downloadError.Message, "下载错误", "IconX")
AddLog(latestObj.display_name . " 下载失败: " . downloadError.Message)
if FileExist(A_ScriptDir "\" downloadTempName) {
try {
FileDelete(A_ScriptDir "\" downloadTempName)
} catch {
; 忽略删除临时文件失败
}
}
}
}
;tag 点击检查更新
ClickOnCheckForUpdate(*) {
; if InStr(currentVersion, "beta") {
; MsgBox ("测试版本禁用更新!")
; MsgBox ("请加群584275905")
; Pause
; }
CheckForUpdateHandler(true) ;调用核心函数,标记为手动检查
AddLog("=== 更新检查启动 (手动) ===")
CheckForUpdate(true)
}
;tag 版本比较
CompareVersionsSemVer(v1, v2) {
_IsNumericString(str) => RegExMatch(str, "^\d+$")
v1 := RegExReplace(v1, "^v", "")
v2 := RegExReplace(v2, "^v", "")
v1Parts := StrSplit(v1, "+", , 2)
v2Parts := StrSplit(v2, "+", , 2)
v1Base := v1Parts[1]
v2Base := v2Parts[1]
v1CoreParts := StrSplit(v1Base, "-", , 2)
v2CoreParts := StrSplit(v2Base, "-", , 2)
v1Core := v1CoreParts[1]
v2Core := v2CoreParts[1]
v1Pre := v1CoreParts.Length > 1 ? v1CoreParts[2] : ""
v2Pre := v2CoreParts.Length > 1 ? v2CoreParts[2] : ""
v1CoreNums := StrSplit(v1Core, ".")
v2CoreNums := StrSplit(v2Core, ".")
loop 3 {
local seg1Str := A_Index <= v1CoreNums.Length ? Trim(v1CoreNums[A_Index]) : "0"
local seg2Str := A_Index <= v2CoreNums.Length ? Trim(v2CoreNums[A_Index]) : "0"
if !_IsNumericString(seg1Str) {
seg1Str := "0"
}
if !_IsNumericString(seg2Str) {
seg2Str := "0"
}
num1 := Integer(seg1Str)
num2 := Integer(seg2Str)
if (num1 > num2) {
return 1
}
if (num1 < num2) {
return -1
}
}
hasV1Pre := v1Pre != ""
hasV2Pre := v2Pre != ""
if (hasV1Pre && !hasV2Pre) {
return -1
}
if (!hasV1Pre && hasV2Pre) {
return 1
}
if (!hasV1Pre && !hasV2Pre) {
return 0
}
v1PreSegments := StrSplit(v1Pre, ".")
v2PreSegments := StrSplit(v2Pre, ".")
maxLen := Max(v1PreSegments.Length, v2PreSegments.Length)
loop maxLen {
if (A_Index > v1PreSegments.Length) {
return -1
}
if (A_Index > v2PreSegments.Length) {
return 1
}
seg1 := Trim(v1PreSegments[A_Index])
seg2 := Trim(v2PreSegments[A_Index])
isNum1 := _IsNumericString(seg1)
isNum2 := _IsNumericString(seg2)
if (isNum1 && isNum2) {
numSeg1 := Integer(seg1)
numSeg2 := Integer(seg2)
if (numSeg1 > numSeg2)
return 1
if (numSeg1 < numSeg2)
return -1
} else if (!isNum1 && !isNum2) {
; 强制进行字符串比较
compareResult := StrCompare(seg1, seg2)
if (compareResult > 0)
return 1
if (compareResult < 0)
return -1
} else {
if (isNum1)
return -1
if (isNum2)
return 1
}
}
return 0
}
;endregion 软件更新
;region 消息辅助函数