From 58bf32f6fba52a64d59390756a3fd33db8c8ce0c Mon Sep 17 00:00:00 2001 From: NULL_Cirno <41545185+Cirno-NULL@users.noreply.github.com> Date: Mon, 9 Jun 2025 11:04:44 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 详情见ReadMe --- deps/tools/quick_update/ReadMe.md | 30 +++ deps/tools/quick_update/download_MAA_fw.py | 234 +++++++++++++++++++++ 2 files changed, 264 insertions(+) create mode 100644 deps/tools/quick_update/ReadMe.md create mode 100644 deps/tools/quick_update/download_MAA_fw.py diff --git a/deps/tools/quick_update/ReadMe.md b/deps/tools/quick_update/ReadMe.md new file mode 100644 index 00000000..c176fca9 --- /dev/null +++ b/deps/tools/quick_update/ReadMe.md @@ -0,0 +1,30 @@ +# 更新脚本 +用于自动更新`MaaFramework`框架到本地的`deps`文件夹 + +逻辑采用覆盖安装 + +运行的时候会自行切换到py文件所在路径 + +运行时附带后缀`--debug`将无视本地已有文件进行下载 + +运行时附带后缀`--unzip`将无视所有代码只进行解压测试 + +默认更新`releases/latest`所提供的`MaaFramework`框架 + +默认自动选择更新包 + +如需手动选择请遵循提示按n或者N然后回车 + +手动选择请遵循提示进行选择 + +更新完成后会在`.\deps\tools\quick_update`路径下 +保留一份`MaaFramework.zip`和一份`version.txt`用来快速解压和校验版本 +``` +deps +│ +└─tools + │ + └─quick_update + MaaFramework.zip + version.txt +``` \ No newline at end of file diff --git a/deps/tools/quick_update/download_MAA_fw.py b/deps/tools/quick_update/download_MAA_fw.py new file mode 100644 index 00000000..6b2e8e79 --- /dev/null +++ b/deps/tools/quick_update/download_MAA_fw.py @@ -0,0 +1,234 @@ +import os +import sys +import zipfile + +import requests +import platform +import time + + +def detect_os(): + sys_platform = sys.platform + if sys_platform.startswith("linux"): + # 判断是不是安卓(Termux) + import os + if "ANDROID_ROOT" in os.environ: + return "android" + return "linux" + elif sys_platform == "darwin": + return "macos" + elif sys_platform in ("win32", "cygwin"): + return "win" + else: + return "unknown" + + +def detect_arch(): + machine = platform.machine().lower() + if machine in ("x86_64", "amd64"): + return "x86_64" + elif "aarch64" in machine or "arm64" in machine: + return "aarch64" + else: + return "unknown" + + +def get_github_download_options(): + try: + response = requests.get( + "https://api.github.com/repos/MaaXYZ/MaaFramework/releases/latest", + timeout=10 + ) + response.raise_for_status() # 如果状态码不是200则抛出异常 + + assets = response.json().get("assets", []) + + if not assets: + print("该发布版未包含任何可下载资源") + return None + + # 创建结构化资源列表 + resource_list = [] + print("\n可用的下载选项:") + for idx, asset in enumerate(assets): + size_mb = asset['size'] / (1024 * 1024) + print(f"{idx}. {asset['name']} ({size_mb:.2f} MB)") + + # 将资源信息添加到列表 + resource_list.append({ + "index": idx, # 从0开始的索引 + "name": asset['name'], + "url": asset['browser_download_url'], + "size": asset['size'], + "size_mb": size_mb + }) + + return resource_list + + except requests.exceptions.RequestException as e: + print(f"获取发布信息失败: {str(e)}") + return None + except (KeyError, IndexError, TypeError) as e: + print(f"解析数据出错: {str(e)}") + return None + + +def select_download_resource(resource_list, auto=False): + combo_key = None + if not resource_list: + print("没有可用的下载资源") + return None + else: + os_name = detect_os() + arch_name = detect_arch() + combo_key = f"{os_name}-{arch_name}" + print("检测结果:", combo_key) + + if auto: + matched = next( + (item for item in resource_list if combo_key in item['name']), None) + if matched: + print(f"找到下载包: {matched['name']}") + print(f"下载链接: {matched['url']}") + print(f"大小: {matched['size_mb']} MB") + return matched['url'] + else: + print("没有找到适配的版本。") + return False + else: + while True: + try: + choice = input("\n请输入要下载的选项编号 (输入 'q' 退出): ") + if choice.lower() == 'q': + return False + + choice_idx = int(choice) # 转换为0开始的索引 + + if 0 <= choice_idx < len(resource_list): + return resource_list[choice_idx]["url"] + else: + print(f"无效的选择,请输入 1-{len(resource_list)} 之间的数字") + + except ValueError: + print("请输入有效的数字") + + +def read_version(): + with open("version.txt", "a", encoding='utf-8') as f: + f.close() + with open("version.txt", "r", encoding='utf-8') as f: + data = f.read() + f.close() + return data + + +def check_version(version_url, version_txt): + if version_url == version_txt: + print("已经是最新版本了,不需要更新") + return False + else: + print("不是最新版本") + return True + + +def download_file(url, url_ver): + r = requests.get( + url, + allow_redirects=True, + stream=True, + timeout=10 + ) + with open("version.txt", "w", encoding='utf-8') as f: + f.write(url_ver) + f.close() + + with open("MaaFramework.zip", "wb") as f: + for chunk in r.iter_content(chunk_size=8192): + f.write(chunk) + + +def unzip(filename, target_dir=None): + """ + 解压ZIP文件到指定目录 + + 参数: + filename -- 要解压的ZIP文件名 + target_dir -- 解压目标目录(默认为当前目录) + """ + # 如果没有指定目标目录,询问用户 + if target_dir is None: + target_dir = input("请输入解压路径(留空则解压到上两级目录): ").strip() + + # 如果留空,使用当前目录(或者在此自定义路径) + if not target_dir: + target_dir = "../../" + + # 创建目标目录(如果不存在) + os.makedirs(target_dir, exist_ok=True) + + print(f"正在解压 {filename} 到 {os.path.abspath(target_dir)}...") + + try: + with zipfile.ZipFile(filename, 'r') as zip_ref: + file_list = zip_ref.namelist() + + total_files = len(file_list) + for i, file in enumerate(file_list, 1): + zip_ref.extract(file, target_dir) + # 每解压10个文件显示一次进度 + if i % 10 == 0 or i == total_files: + print(f"解压进度: {i}/{total_files} ({i/total_files:.0%})") + + print("解压完成!") + return True + except zipfile.BadZipFile: + print(f"错误: {filename} 不是有效的ZIP文件") + return False + except FileNotFoundError: + print(f"错误: 文件 {filename} 不存在") + return False + except Exception as e: + print(f"解压过程中发生错误: {str(e)}") + return False + + +def main(isdebug=False): + if isdebug: + print("处于调试模式,将无视版本进行下载") + print("正在获取最新版本信息", end=":\t") + download_options = get_github_download_options() + auto_update = input("\n输入n或者N并且按回车\n关闭自动选择更新包功能\n") + if auto_update in ["N", "n"]: + auto_update = False + else: + auto_update = True + url_ver = select_download_resource(download_options, auto_update) + print("正在获取本地版本信息", end=":\t") + file_ver = read_version() + print(file_ver) + if url_ver == False: + print("网络错误或者手动退出,无法更新") + return + print("网络正常,与最新版本信息比较中") + + if check_version(url_ver, file_ver) or isdebug: + url = url_ver + print(url) + print("正在下载文件") + download_file(url, url_ver) + print("正在解压文件") + unzip("MaaFramework.zip") + print("解压完成") + + +print("正在切换工作路径至exe所在路径") +os.chdir(os.path.dirname(os.path.realpath(sys.argv[0]))) +if "--debug" in sys.argv: + main(True) +elif "--unzip" in sys.argv: # 仅进行本地压缩包解压,不下载 + unzip("MaaFramework.zip") +else: + main() + + +os.system("pause") From 63272ed3bdd860d566f8fc759420f7194fcc72d4 Mon Sep 17 00:00:00 2001 From: NULL_Cirno <41545185+Cirno-NULL@users.noreply.github.com> Date: Mon, 9 Jun 2025 14:15:38 +0800 Subject: [PATCH 2/9] Update download_MAA_fw.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 通过检查dll的形式来获取版本号 --- deps/tools/quick_update/download_MAA_fw.py | 210 ++++++++++++++------- 1 file changed, 147 insertions(+), 63 deletions(-) diff --git a/deps/tools/quick_update/download_MAA_fw.py b/deps/tools/quick_update/download_MAA_fw.py index 6b2e8e79..f377bc9e 100644 --- a/deps/tools/quick_update/download_MAA_fw.py +++ b/deps/tools/quick_update/download_MAA_fw.py @@ -1,10 +1,10 @@ import os import sys import zipfile - +import ctypes import requests import platform -import time +from typing import Optional, List, Generator def detect_os(): @@ -33,7 +33,103 @@ def detect_arch(): return "unknown" +def get_local_version_from_dll(dll_path: str) -> Optional[str]: + """尝试从本地dll获取maafw版本 + + Arguments: + dll_path {str} -- dll路径 + + Returns: + Optional[str] -- dll版本 + """ + try: + # 尝试加载 DLL + lib = ctypes.CDLL(dll_path) + + # 检查是否存在 MaaVersion 函数 + if not hasattr(lib, 'MaaVersion'): + return None + + # 设置函数签名 + lib.MaaVersion.restype = ctypes.c_char_p + lib.MaaVersion.argtypes = [] + + # 调用函数并返回解码后的字符串 + version_bytes = lib.MaaVersion() + return version_bytes.decode('utf-8') + + except (OSError, AttributeError, ctypes.ArgumentError): + # 捕获所有可能的加载/调用异常 + return None + + +def get_local_platform(): + """获取本地版本地址 + + Returns: + str -- 版本号 + """ + os_name = detect_os() + arch_name = detect_arch() + combo_key = f"{os_name}-{arch_name}" + print("检测结果:", combo_key) + return combo_key + + +def auto_ver_select(resource_list, combo_key): + """自动选择版本 + + Arguments: + resource_list {list} -- 通过Release获取到的列表 + combo_key {str} -- 识别到的版本 + + Returns: + str -- 下载路径或者是False + 如果是False则不进行下载 + """ + matched = next( + (item for item in resource_list if combo_key in item['name']), None) + if matched: + print(f"找到下载包: {matched['name']}") + print(f"下载链接: {matched['url']}") + print(f"大小: {matched['size_mb']} MB") + return matched['url'] + else: + print("没有找到适配的版本。") + return False + + +def custum_ver_select(resource_list): + """用户自行选择下载包 + + Arguments: + resource_list {list} -- 通过Release获取到的列表 + + Returns: + str -- 下载路径或者是False + 如果是False则不进行下载 + """ + while True: + try: + choice = input("\n请输入要下载的选项编号 (输入 'q' 退出): ") + if choice.lower() == 'q': + return False + choice_idx = int(choice) # 转换为0开始的索引 + if 0 <= choice_idx < len(resource_list): + return resource_list[choice_idx]["url"] + else: + print(f"无效的选择,请输入 1-{len(resource_list)} 之间的数字") + except ValueError: + print("请输入有效的数字") + + def get_github_download_options(): + """获取Github的最新版本下载列表 + + Returns: + list -- 下载版本合集 + 或者是None,说明下载出问题了 + """ try: response = requests.get( "https://api.github.com/repos/MaaXYZ/MaaFramework/releases/latest", @@ -74,74 +170,50 @@ def get_github_download_options(): def select_download_resource(resource_list, auto=False): + """选择下载包 + + Arguments: + resource_list {list} -- 通过Release获取到的列表 + + Keyword Arguments: + auto {bool} -- 是否自动选择下载包 (default: {False}) + + Returns: + str -- 下载路径或者是False + 如果是False则不进行下载 + """ combo_key = None if not resource_list: print("没有可用的下载资源") return None + elif auto: + combo_key = get_local_platform() + return auto_ver_select(resource_list, combo_key) else: - os_name = detect_os() - arch_name = detect_arch() - combo_key = f"{os_name}-{arch_name}" - print("检测结果:", combo_key) - - if auto: - matched = next( - (item for item in resource_list if combo_key in item['name']), None) - if matched: - print(f"找到下载包: {matched['name']}") - print(f"下载链接: {matched['url']}") - print(f"大小: {matched['size_mb']} MB") - return matched['url'] - else: - print("没有找到适配的版本。") - return False - else: - while True: - try: - choice = input("\n请输入要下载的选项编号 (输入 'q' 退出): ") - if choice.lower() == 'q': - return False + return custum_ver_select(resource_list) - choice_idx = int(choice) # 转换为0开始的索引 - if 0 <= choice_idx < len(resource_list): - return resource_list[choice_idx]["url"] - else: - print(f"无效的选择,请输入 1-{len(resource_list)} 之间的数字") +def check_version(file_ver, url_ver): + """检查是否包含对应版本 - except ValueError: - print("请输入有效的数字") + Arguments: + file_ver {str} -- 本地dll版本 + url_ver {str} -- 网页链接 - -def read_version(): - with open("version.txt", "a", encoding='utf-8') as f: - f.close() - with open("version.txt", "r", encoding='utf-8') as f: - data = f.read() - f.close() - return data - - -def check_version(version_url, version_txt): - if version_url == version_txt: - print("已经是最新版本了,不需要更新") - return False - else: - print("不是最新版本") - return True + Returns: + bool -- 如果包含,返回True,是最新版本 + 如果不包含,返回False,不是最新版本 + """ + return file_ver in url_ver -def download_file(url, url_ver): +def download_file(url): r = requests.get( url, allow_redirects=True, stream=True, timeout=10 ) - with open("version.txt", "w", encoding='utf-8') as f: - f.write(url_ver) - f.close() - with open("MaaFramework.zip", "wb") as f: for chunk in r.iter_content(chunk_size=8192): f.write(chunk) @@ -195,30 +267,36 @@ def unzip(filename, target_dir=None): def main(isdebug=False): if isdebug: print("处于调试模式,将无视版本进行下载") + print("正在获取最新版本信息", end=":\t") download_options = get_github_download_options() + if download_options is None: + print("网络错误或者手动退出,无法更新") + return None + auto_update = input("\n输入n或者N并且按回车\n关闭自动选择更新包功能\n") if auto_update in ["N", "n"]: auto_update = False else: auto_update = True + + print("正在获取本地版本信息", end=":\n") + file_ver = get_local_version_from_dll("../../bin/MaaFramework.dll") + print(f"本地版本:{file_ver}") + url_ver = select_download_resource(download_options, auto_update) - print("正在获取本地版本信息", end=":\t") - file_ver = read_version() - print(file_ver) - if url_ver == False: - print("网络错误或者手动退出,无法更新") - return - print("网络正常,与最新版本信息比较中") - if check_version(url_ver, file_ver) or isdebug: + print("网络正常,与最新版本信息比较中") + if check_version(file_ver, url_ver) is False or isdebug: url = url_ver print(url) print("正在下载文件") - download_file(url, url_ver) + download_file(url) print("正在解压文件") unzip("MaaFramework.zip") print("解压完成") + else: + print("已是最新版本,无需更新") print("正在切换工作路径至exe所在路径") @@ -227,8 +305,14 @@ def main(isdebug=False): main(True) elif "--unzip" in sys.argv: # 仅进行本地压缩包解压,不下载 unzip("MaaFramework.zip") +elif "--check_version" in sys.argv: # 仅进行版本检查,不下载 + file_ver = get_local_version_from_dll("../../bin/MaaFramework.dll") + print(file_ver) + url_ver = select_download_resource(get_github_download_options(), True) + print(url_ver) + check_resalt = check_version(file_ver, url_ver) + print(check_resalt) else: main() - os.system("pause") From 76a055b9c53f92d7f2f09619af6bfd59d7aa4721 Mon Sep 17 00:00:00 2001 From: NULL_Cirno <41545185+Cirno-NULL@users.noreply.github.com> Date: Mon, 9 Jun 2025 14:16:24 +0800 Subject: [PATCH 3/9] Update ReadMe.md --- deps/tools/quick_update/ReadMe.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deps/tools/quick_update/ReadMe.md b/deps/tools/quick_update/ReadMe.md index c176fca9..fa70f7d1 100644 --- a/deps/tools/quick_update/ReadMe.md +++ b/deps/tools/quick_update/ReadMe.md @@ -9,6 +9,8 @@ 运行时附带后缀`--unzip`将无视所有代码只进行解压测试 +运行时附带后缀`--check_version`将进行一次版本检查,不会下载 + 默认更新`releases/latest`所提供的`MaaFramework`框架 默认自动选择更新包 @@ -27,4 +29,4 @@ deps └─quick_update MaaFramework.zip version.txt -``` \ No newline at end of file +``` From 887683e6f515582fbace0ad3f475b0053a5cd64f Mon Sep 17 00:00:00 2001 From: NULL_Cirno <41545185+Cirno-NULL@users.noreply.github.com> Date: Mon, 9 Jun 2025 16:04:26 +0800 Subject: [PATCH 4/9] Update download_MAA_fw.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 应该是不需要再修改了吧 --- deps/tools/quick_update/download_MAA_fw.py | 161 +++++++++++++++++---- 1 file changed, 130 insertions(+), 31 deletions(-) diff --git a/deps/tools/quick_update/download_MAA_fw.py b/deps/tools/quick_update/download_MAA_fw.py index f377bc9e..7a00bd74 100644 --- a/deps/tools/quick_update/download_MAA_fw.py +++ b/deps/tools/quick_update/download_MAA_fw.py @@ -1,10 +1,13 @@ +import ctypes import os +import platform import sys import zipfile -import ctypes +from ctypes import wintypes +from pathlib import Path +from typing import Optional + import requests -import platform -from typing import Optional, List, Generator def detect_os(): @@ -34,34 +37,77 @@ def detect_arch(): def get_local_version_from_dll(dll_path: str) -> Optional[str]: - """尝试从本地dll获取maafw版本 + """安全地从本地 DLL 获取 maafw 版本并卸载 DLL Arguments: - dll_path {str} -- dll路径 + dll_path {str} -- DLL 路径 Returns: - Optional[str] -- dll版本 + Optional[str] -- DLL 版本,失败时返回 None """ + # 确保路径是绝对路径 + dll_path = os.path.abspath(dll_path) + + # 1. 尝试加载 DLL try: - # 尝试加载 DLL - lib = ctypes.CDLL(dll_path) + # 使用 WinDLL 以便获取句柄 + lib = ctypes.WinDLL(dll_path) + except OSError as e: + print(f"加载 DLL 失败: {e}", file=sys.stderr) + return None + + # 记录句柄用于后续卸载 + dll_handle = lib._handle - # 检查是否存在 MaaVersion 函数 + try: + # 2. 检查是否存在 MaaVersion 函数 if not hasattr(lib, 'MaaVersion'): + print(f"DLL 缺少 MaaVersion 函数: {dll_path}", file=sys.stderr) return None - # 设置函数签名 + # 3. 设置函数签名 lib.MaaVersion.restype = ctypes.c_char_p lib.MaaVersion.argtypes = [] - # 调用函数并返回解码后的字符串 + # 4. 调用函数获取版本 version_bytes = lib.MaaVersion() + + # 确保返回的是 bytes + if not isinstance(version_bytes, bytes): + print("MaaVersion 返回无效类型", file=sys.stderr) + return None + return version_bytes.decode('utf-8') - except (OSError, AttributeError, ctypes.ArgumentError): - # 捕获所有可能的加载/调用异常 + except (AttributeError, ctypes.ArgumentError) as e: + print(f"调用 DLL 函数出错: {e}", file=sys.stderr) return None + finally: + # 5. 无论如何都尝试卸载 DLL + _safe_unload_dll(dll_handle) + + +def _safe_unload_dll(handle: int) -> bool: + """安全卸载 DLL + + Arguments: + handle {int} -- DLL 句柄 + + Returns: + bool -- 是否成功卸载 + """ + try: + if handle and kernel32.FreeLibrary(handle): + return True + return False + except Exception as e: + print(f"卸载 DLL 失败: {e}", file=sys.stderr) + return False + finally: + # 清除引用,帮助垃圾回收 + del handle + def get_local_platform(): """获取本地版本地址 @@ -116,6 +162,7 @@ def custum_ver_select(resource_list): return False choice_idx = int(choice) # 转换为0开始的索引 if 0 <= choice_idx < len(resource_list): + print(f"下载链接: {resource_list[choice_idx]['url']}") return resource_list[choice_idx]["url"] else: print(f"无效的选择,请输入 1-{len(resource_list)} 之间的数字") @@ -243,16 +290,24 @@ def unzip(filename, target_dir=None): try: with zipfile.ZipFile(filename, 'r') as zip_ref: file_list = zip_ref.namelist() - total_files = len(file_list) + for i, file in enumerate(file_list, 1): zip_ref.extract(file, target_dir) - # 每解压10个文件显示一次进度 - if i % 10 == 0 or i == total_files: - print(f"解压进度: {i}/{total_files} ({i/total_files:.0%})") - print("解压完成!") - return True + # 计算进度百分比 + progress = i / total_files + # 构造进度条字符串(50字符宽度) + bar_length = 50 + bar = '█' * int(bar_length * progress) + percent = f"{progress:.0%}" + # 使用回车符覆盖当前行 + print( + f"\r解压进度: [{bar:<{bar_length}}] {percent} ({i}/{total_files})", end="") + + # 最后换行 + print("\n解压完成!") + return True except zipfile.BadZipFile: print(f"错误: {filename} 不是有效的ZIP文件") return False @@ -264,8 +319,35 @@ def unzip(filename, target_dir=None): return False -def main(isdebug=False): - if isdebug: +def delete_file(filename): + """安全删除文件并处理所有异常""" + try: + # 使用 pathlib 处理路径更安全 + file_path = Path(filename) + + # 检查是否为文件(避免误删目录) + if file_path.is_file(): + # 实际删除文件 + file_path.unlink() + print(f"文件 '{filename}' 已成功删除") + return True + elif file_path.exists(): + print(f"'{filename}' 是目录而非文件") + return False + else: + print(f"文件 '{filename}' 不存在,无需删除") + return False + + except PermissionError: + print(f"没有权限删除 '{filename}'") + return False + except Exception as e: + print(f"删除文件时出错: {e}") + return False + + +def main(is_debug=False, is_delete=True): + if is_debug: print("处于调试模式,将无视版本进行下载") print("正在获取最新版本信息", end=":\t") @@ -281,38 +363,55 @@ def main(isdebug=False): auto_update = True print("正在获取本地版本信息", end=":\n") - file_ver = get_local_version_from_dll("../../bin/MaaFramework.dll") + file_ver = get_local_version_from_dll(dll_path) print(f"本地版本:{file_ver}") url_ver = select_download_resource(download_options, auto_update) print("网络正常,与最新版本信息比较中") - if check_version(file_ver, url_ver) is False or isdebug: + if check_version(file_ver, url_ver) is False or is_debug or is_delete is False: + print(f"\n当前版本{check_version(file_ver, url_ver)}最新版本\n") url = url_ver - print(url) - print("正在下载文件") - download_file(url) + print("正在下载文件MaaFramework.zip") + # download_file(url) print("正在解压文件") unzip("MaaFramework.zip") print("解压完成") else: print("已是最新版本,无需更新") + if is_debug: + pass + elif is_delete: + delete_file("MaaFramework.zip") + print("正在切换工作路径至exe所在路径") os.chdir(os.path.dirname(os.path.realpath(sys.argv[0]))) -if "--debug" in sys.argv: - main(True) -elif "--unzip" in sys.argv: # 仅进行本地压缩包解压,不下载 + +kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) +kernel32.FreeLibrary.argtypes = [wintypes.HMODULE] +kernel32.FreeLibrary.restype = wintypes.BOOL +dll_path = os.path.abspath("../../bin/MaaFramework.dll") + + +if "--unzip" in sys.argv: # 仅进行本地压缩包解压,不下载 unzip("MaaFramework.zip") elif "--check_version" in sys.argv: # 仅进行版本检查,不下载 - file_ver = get_local_version_from_dll("../../bin/MaaFramework.dll") + file_ver = get_local_version_from_dll(dll_path) print(file_ver) url_ver = select_download_resource(get_github_download_options(), True) print(url_ver) check_resalt = check_version(file_ver, url_ver) print(check_resalt) else: - main() + is_debug = False + is_delete = True + if "--debug" in sys.argv: # 无视版本进行下载,下载完成后不删除压缩包 + is_debug = True + if "--not_delete" in sys.argv: # 解压完成后不删除压缩包 + is_delete = False + main(is_debug=is_debug, is_delete=is_delete) + os.system("pause") From 670a88af8eba2a6bf439be09d607582c2ee0a53c Mon Sep 17 00:00:00 2001 From: NULL_Cirno <41545185+Cirno-NULL@users.noreply.github.com> Date: Mon, 9 Jun 2025 16:06:59 +0800 Subject: [PATCH 5/9] Update ReadMe.md --- deps/tools/quick_update/ReadMe.md | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/deps/tools/quick_update/ReadMe.md b/deps/tools/quick_update/ReadMe.md index fa70f7d1..637bcfb8 100644 --- a/deps/tools/quick_update/ReadMe.md +++ b/deps/tools/quick_update/ReadMe.md @@ -5,7 +5,9 @@ 运行的时候会自行切换到py文件所在路径 -运行时附带后缀`--debug`将无视本地已有文件进行下载 +运行时附带后缀`--debug`将无视本地已有文件进行下载,下载完成不会删除已下载的压缩包 + +运行时附带后缀`--not_delete`将不会删除已下载的压缩包 运行时附带后缀`--unzip`将无视所有代码只进行解压测试 @@ -18,15 +20,3 @@ 如需手动选择请遵循提示按n或者N然后回车 手动选择请遵循提示进行选择 - -更新完成后会在`.\deps\tools\quick_update`路径下 -保留一份`MaaFramework.zip`和一份`version.txt`用来快速解压和校验版本 -``` -deps -│ -└─tools - │ - └─quick_update - MaaFramework.zip - version.txt -``` From 7d6d8f7a2e87a756ecd8ee1a4b3705a42abc07be Mon Sep 17 00:00:00 2001 From: NULL_Cirno <41545185+Cirno-NULL@users.noreply.github.com> Date: Mon, 9 Jun 2025 16:09:07 +0800 Subject: [PATCH 6/9] Update download_MAA_fw.py --- deps/tools/quick_update/download_MAA_fw.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/tools/quick_update/download_MAA_fw.py b/deps/tools/quick_update/download_MAA_fw.py index 7a00bd74..38ac6a55 100644 --- a/deps/tools/quick_update/download_MAA_fw.py +++ b/deps/tools/quick_update/download_MAA_fw.py @@ -373,7 +373,7 @@ def main(is_debug=False, is_delete=True): print(f"\n当前版本{check_version(file_ver, url_ver)}最新版本\n") url = url_ver print("正在下载文件MaaFramework.zip") - # download_file(url) + download_file(url) print("正在解压文件") unzip("MaaFramework.zip") print("解压完成") From f47d4e11f55cfd3d6155ee3a009b9e50ca8bcde3 Mon Sep 17 00:00:00 2001 From: NULL_Cirno <41545185+Cirno-NULL@users.noreply.github.com> Date: Mon, 9 Jun 2025 16:40:46 +0800 Subject: [PATCH 7/9] Update download_MAA_fw.py --- deps/tools/quick_update/download_MAA_fw.py | 44 +++++++++++----------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/deps/tools/quick_update/download_MAA_fw.py b/deps/tools/quick_update/download_MAA_fw.py index 38ac6a55..4ed7cdae 100644 --- a/deps/tools/quick_update/download_MAA_fw.py +++ b/deps/tools/quick_update/download_MAA_fw.py @@ -391,27 +391,29 @@ def main(is_debug=False, is_delete=True): kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) kernel32.FreeLibrary.argtypes = [wintypes.HMODULE] -kernel32.FreeLibrary.restype = wintypes.BOOL dll_path = os.path.abspath("../../bin/MaaFramework.dll") -if "--unzip" in sys.argv: # 仅进行本地压缩包解压,不下载 - unzip("MaaFramework.zip") -elif "--check_version" in sys.argv: # 仅进行版本检查,不下载 - file_ver = get_local_version_from_dll(dll_path) - print(file_ver) - url_ver = select_download_resource(get_github_download_options(), True) - print(url_ver) - check_resalt = check_version(file_ver, url_ver) - print(check_resalt) -else: - is_debug = False - is_delete = True - if "--debug" in sys.argv: # 无视版本进行下载,下载完成后不删除压缩包 - is_debug = True - if "--not_delete" in sys.argv: # 解压完成后不删除压缩包 - is_delete = False - main(is_debug=is_debug, is_delete=is_delete) - - -os.system("pause") +if __name__ == "__main__": + if "--unzip" in sys.argv: # 仅进行本地压缩包解压,不下载 + print("仅进行本地压缩包解压,不下载") + unzip("MaaFramework.zip") + elif "--check_version" in sys.argv: # 仅进行版本检查,不下载 + print("仅进行版本检查,不下载") + file_ver = get_local_version_from_dll(dll_path) + print(file_ver) + url_ver = select_download_resource(get_github_download_options(), True) + print(url_ver) + check_resalt = check_version(file_ver, url_ver) + print(check_resalt) + else: + is_debug = False + is_delete = True + if "--debug" in sys.argv: # 无视版本进行下载,下载完成后不删除压缩包 + print("--debug 将无视版本检查进行下载,下载完成后不删除压缩包") + is_debug = True + if "--not_delete" in sys.argv: # 解压完成后不删除压缩包 + print("--not_delete 解压完成后不删除压缩包") + is_delete = False + main(is_debug=is_debug, is_delete=is_delete) + os.system("pause") From 4de7a0045fb19491c4c4e51974865b2fe9d91980 Mon Sep 17 00:00:00 2001 From: NULL_Cirno <41545185+Cirno-NULL@users.noreply.github.com> Date: Mon, 9 Jun 2025 23:39:53 +0800 Subject: [PATCH 8/9] Update download_MAA_fw.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增选择版本的功能 --- deps/tools/quick_update/download_MAA_fw.py | 112 +++++++++++++-------- 1 file changed, 70 insertions(+), 42 deletions(-) diff --git a/deps/tools/quick_update/download_MAA_fw.py b/deps/tools/quick_update/download_MAA_fw.py index 4ed7cdae..f316db8e 100644 --- a/deps/tools/quick_update/download_MAA_fw.py +++ b/deps/tools/quick_update/download_MAA_fw.py @@ -171,39 +171,42 @@ def custum_ver_select(resource_list): def get_github_download_options(): - """获取Github的最新版本下载列表 - - Returns: - list -- 下载版本合集 - 或者是None,说明下载出问题了 - """ + """获取Github的下载选项(前5个版本)""" try: response = requests.get( - "https://api.github.com/repos/MaaXYZ/MaaFramework/releases/latest", + "https://api.github.com/repos/MaaXYZ/MaaFramework/releases", timeout=10 ) - response.raise_for_status() # 如果状态码不是200则抛出异常 - - assets = response.json().get("assets", []) + response.raise_for_status() - if not assets: - print("该发布版未包含任何可下载资源") + releases = response.json() + if not releases: + print("未找到任何发布版本") return None - # 创建结构化资源列表 - resource_list = [] - print("\n可用的下载选项:") - for idx, asset in enumerate(assets): - size_mb = asset['size'] / (1024 * 1024) - print(f"{idx}. {asset['name']} ({size_mb:.2f} MB)") + # 只取前5个版本 + recent_releases = releases[:5] - # 将资源信息添加到列表 + resource_list = [] + print("\n可用的版本:") + for idx, release in enumerate(recent_releases): + version = release['tag_name'] + print(f"{idx}. {version}") + # 收集该版本的资源 + assets = release.get("assets", []) + asset_list = [] + for asset_idx, asset in enumerate(assets): + size_mb = asset['size'] / (1024 * 1024) + asset_list.append({ + "index": asset_idx, + "name": asset['name'], + "url": asset['browser_download_url'], + "size": asset['size'], + "size_mb": size_mb + }) resource_list.append({ - "index": idx, # 从0开始的索引 - "name": asset['name'], - "url": asset['browser_download_url'], - "size": asset['size'], - "size_mb": size_mb + "version": version, + "assets": asset_list }) return resource_list @@ -217,27 +220,51 @@ def get_github_download_options(): def select_download_resource(resource_list, auto=False): - """选择下载包 - - Arguments: - resource_list {list} -- 通过Release获取到的列表 - - Keyword Arguments: - auto {bool} -- 是否自动选择下载包 (default: {False}) - - Returns: - str -- 下载路径或者是False - 如果是False则不进行下载 - """ - combo_key = None + """选择下载资源(先选版本,再选资源)""" if not resource_list: print("没有可用的下载资源") return None - elif auto: + + # 自动模式:使用最新版本 + if auto: + latest_release = resource_list[0] + assets = latest_release['assets'] combo_key = get_local_platform() - return auto_ver_select(resource_list, combo_key) - else: - return custum_ver_select(resource_list) + return auto_ver_select(assets, combo_key) + + # 手动模式:选择版本 + print("\n请选择版本:") + for idx, release in enumerate(resource_list): + print(f"{idx}. {release['version']}") + + while True: + try: + choice = input("\n请输入版本编号 (输入 'q' 退出): ") + if choice.lower() == 'q': + return False + + version_idx = int(choice) + if 0 <= version_idx < len(resource_list): + selected_release = resource_list[version_idx] + print(f"\n已选择版本: {selected_release['version']}") + + # 显示该版本的资源 + assets = selected_release['assets'] + # print(assets) + if not assets: + print("该版本没有可用的资源") + return False + + print("\n可用的资源:") + for idx, asset in enumerate(assets): + print( + f"{idx}. {asset['name']} ({asset['size_mb']:.2f} MB)") + + return custum_ver_select(assets) + else: + print(f"无效的选择,请输入 0-{len(resource_list)-1} 之间的数字") + except ValueError: + print("请输入有效的数字") def check_version(file_ver, url_ver): @@ -402,7 +429,8 @@ def main(is_debug=False, is_delete=True): print("仅进行版本检查,不下载") file_ver = get_local_version_from_dll(dll_path) print(file_ver) - url_ver = select_download_resource(get_github_download_options(), True) + url_ver = select_download_resource( + get_github_download_options(), False) print(url_ver) check_resalt = check_version(file_ver, url_ver) print(check_resalt) From 1294dfaf8c87ac5c2d382876bc3d4bee53599545 Mon Sep 17 00:00:00 2001 From: NULL_Cirno <41545185+Cirno-NULL@users.noreply.github.com> Date: Wed, 11 Jun 2025 13:35:11 +0800 Subject: [PATCH 9/9] Update download_MAA_fw.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 稍微优化一下 --- deps/tools/quick_update/download_MAA_fw.py | 142 ++++++++++++--------- 1 file changed, 81 insertions(+), 61 deletions(-) diff --git a/deps/tools/quick_update/download_MAA_fw.py b/deps/tools/quick_update/download_MAA_fw.py index f316db8e..8fe28f5a 100644 --- a/deps/tools/quick_update/download_MAA_fw.py +++ b/deps/tools/quick_update/download_MAA_fw.py @@ -11,6 +11,11 @@ def detect_os(): + """Detect the current operating system. + + Returns: + str: "android" | "linux" | "macos" | "win" | "unknown" + """ sys_platform = sys.platform if sys_platform.startswith("linux"): # 判断是不是安卓(Termux) @@ -27,6 +32,15 @@ def detect_os(): def detect_arch(): + """ + Detect the architecture of the current machine. + + Returns: + str: "x86_64" if the machine is 64-bit Intel/AMD architecture, + "aarch64" if the machine is 64-bit ARM architecture, + or "unknown" if the architecture cannot be determined. + """ + machine = platform.machine().lower() if machine in ("x86_64", "amd64"): return "x86_64" @@ -54,7 +68,7 @@ def get_local_version_from_dll(dll_path: str) -> Optional[str]: lib = ctypes.WinDLL(dll_path) except OSError as e: print(f"加载 DLL 失败: {e}", file=sys.stderr) - return None + return "NONE" # 记录句柄用于后续卸载 dll_handle = lib._handle @@ -63,7 +77,7 @@ def get_local_version_from_dll(dll_path: str) -> Optional[str]: # 2. 检查是否存在 MaaVersion 函数 if not hasattr(lib, 'MaaVersion'): print(f"DLL 缺少 MaaVersion 函数: {dll_path}", file=sys.stderr) - return None + return "NONE" # 3. 设置函数签名 lib.MaaVersion.restype = ctypes.c_char_p @@ -75,13 +89,13 @@ def get_local_version_from_dll(dll_path: str) -> Optional[str]: # 确保返回的是 bytes if not isinstance(version_bytes, bytes): print("MaaVersion 返回无效类型", file=sys.stderr) - return None + return "NONE" return version_bytes.decode('utf-8') except (AttributeError, ctypes.ArgumentError) as e: print(f"调用 DLL 函数出错: {e}", file=sys.stderr) - return None + return "NONE" finally: # 5. 无论如何都尝试卸载 DLL @@ -172,61 +186,64 @@ def custum_ver_select(resource_list): def get_github_download_options(): """获取Github的下载选项(前5个版本)""" + url = "https://api.github.com/repos/MaaXYZ/MaaFramework/releases" try: - response = requests.get( - "https://api.github.com/repos/MaaXYZ/MaaFramework/releases", - timeout=10 - ) + response = requests.get(url, timeout=10) response.raise_for_status() - - releases = response.json() - if not releases: - print("未找到任何发布版本") - return None - - # 只取前5个版本 - recent_releases = releases[:5] - - resource_list = [] - print("\n可用的版本:") - for idx, release in enumerate(recent_releases): - version = release['tag_name'] - print(f"{idx}. {version}") - # 收集该版本的资源 - assets = release.get("assets", []) - asset_list = [] - for asset_idx, asset in enumerate(assets): - size_mb = asset['size'] / (1024 * 1024) - asset_list.append({ - "index": asset_idx, - "name": asset['name'], - "url": asset['browser_download_url'], - "size": asset['size'], - "size_mb": size_mb - }) - resource_list.append({ - "version": version, - "assets": asset_list - }) - - return resource_list - + releases = response.json()[:5] except requests.exceptions.RequestException as e: print(f"获取发布信息失败: {str(e)}") return None - except (KeyError, IndexError, TypeError) as e: - print(f"解析数据出错: {str(e)}") + + if not releases: + print("未找到任何发布版本") return None + resource_list = [] + print("\n可用的版本:") + for idx, release in enumerate(releases): + version = release['tag_name'] + print(f"{idx}. {version}") + assets = release.get("assets", []) + asset_list = [ + { + "index": i, + "name": asset['name'], + "url": asset['browser_download_url'], + "size": asset['size'], + "size_mb": asset['size'] / (1024 * 1024) + } for i, asset in enumerate(assets) + ] + resource_list.append({"version": version, "assets": asset_list}) + + return resource_list + def select_download_resource(resource_list, auto=False): - """选择下载资源(先选版本,再选资源)""" + """ + 选择下载资源 + + 1. 如果 `auto` 是 True,我们将自动选择最新的版本 + 2. 如果 `auto` 是 False,我们将手动选择版本 + 1. 显示所有可用的版本 + 2. 用户选择一个版本 + 3. 显示该版本的所有可用的资源 + 4. 用户选择一个资源 + + Args: + resource_list (list): 一个包含 Release 信息的列表 + auto (bool, optional): 是否自动选择最新的版本. Defaults to False. + + Returns: + str: 下载资源的 URL,如果用户取消,将返回 False + """ if not resource_list: print("没有可用的下载资源") return None # 自动模式:使用最新版本 if auto: + # resource_list[0] 是最新的版本 latest_release = resource_list[0] assets = latest_release['assets'] combo_key = get_local_platform() @@ -241,7 +258,7 @@ def select_download_resource(resource_list, auto=False): try: choice = input("\n请输入版本编号 (输入 'q' 退出): ") if choice.lower() == 'q': - return False + return None version_idx = int(choice) if 0 <= version_idx < len(resource_list): @@ -250,10 +267,9 @@ def select_download_resource(resource_list, auto=False): # 显示该版本的资源 assets = selected_release['assets'] - # print(assets) if not assets: print("该版本没有可用的资源") - return False + return None print("\n可用的资源:") for idx, asset in enumerate(assets): @@ -374,33 +390,31 @@ def delete_file(filename): def main(is_debug=False, is_delete=True): - if is_debug: - print("处于调试模式,将无视版本进行下载") - print("正在获取最新版本信息", end=":\t") download_options = get_github_download_options() if download_options is None: print("网络错误或者手动退出,无法更新") return None - auto_update = input("\n输入n或者N并且按回车\n关闭自动选择更新包功能\n") - if auto_update in ["N", "n"]: - auto_update = False - else: - auto_update = True + auto_update = auto_update_check() print("正在获取本地版本信息", end=":\n") file_ver = get_local_version_from_dll(dll_path) - print(f"本地版本:{file_ver}") + print(f"当前版本:{file_ver}") url_ver = select_download_resource(download_options, auto_update) + if url_ver is None: + print("无法找到最新版本,无法更新") + return None + print(f"本地版本:{file_ver}") + print(f"网络最新版本:{url_ver}") - print("网络正常,与最新版本信息比较中") - if check_version(file_ver, url_ver) is False or is_debug or is_delete is False: - print(f"\n当前版本{check_version(file_ver, url_ver)}最新版本\n") - url = url_ver + # 反转检查结果,为是否最新版本做准备 + checked_version = not check_version(file_ver, url_ver) + if checked_version or is_debug or not is_delete: + print("\n当前版本与选中版本不符,需要更新\n") print("正在下载文件MaaFramework.zip") - download_file(url) + download_file(url_ver) print("正在解压文件") unzip("MaaFramework.zip") print("解压完成") @@ -410,9 +424,15 @@ def main(is_debug=False, is_delete=True): if is_debug: pass elif is_delete: + print("正在删除文件MaaFramework.zip") delete_file("MaaFramework.zip") +def auto_update_check(): + auto_update = input("\n输入n或者N并且按回车\n关闭自动选择更新包功能\n") in ["N", "n"] + return not auto_update + + print("正在切换工作路径至exe所在路径") os.chdir(os.path.dirname(os.path.realpath(sys.argv[0])))