import os import platform import requests import gzip import shutil from zipfile import ZipFile import stat import argparse import subprocess import tempfile # 定义常量 MIHOMO_BASE_URL = 'https://github.com/MetaCubeX/mihomo/releases/download' CORE_SERVICE_BASE_URL = 'https://github.com/alroyso/core-service/releases/download' MIHOMO_VERSION = 'v1.18.8' # 根据实际版本修改 CORE_SERVICE_VERSION = 'v1.0.2' ASSETS_DIR = './assets/bin' SYSTEM = platform.system().lower() # ClashName.platform 和 ClashName.arch 是动态生成的 def get_platform_arch(): return SYSTEM, platform.machine() # 如果目录不存在,创建下载目录 if not os.path.exists(ASSETS_DIR): os.makedirs(ASSETS_DIR) def get_download_urls(): """ 根据系统生成 mihomo 和 core-service 的下载链接,分别下载 arm64 和 x86_64 架构 """ download_urls = [] # 获取 ClashName 的 platform 和 arch platform_name, arch_name = get_platform_arch() # 下载 macOS、Linux、Windows 的 arm64 和 x86_64 架构 if SYSTEM == 'darwin': # macOS download_urls.append(( f'mihomo-darwin-arm64-{MIHOMO_VERSION}.gz', f'{MIHOMO_BASE_URL}/{MIHOMO_VERSION}/mihomo-darwin-arm64-{MIHOMO_VERSION}.gz', 'arm64' )) download_urls.append(( f'mihomo-darwin-amd64-{MIHOMO_VERSION}.gz', f'{MIHOMO_BASE_URL}/{MIHOMO_VERSION}/mihomo-darwin-amd64-{MIHOMO_VERSION}.gz', 'x86_64' )) download_urls.append(( f'ccore-service-darwin-arm64-{CORE_SERVICE_VERSION}.gz', f'{CORE_SERVICE_BASE_URL}/{CORE_SERVICE_VERSION}/ccore-service-darwin-arm64-{CORE_SERVICE_VERSION}.gz', 'arm64' )) download_urls.append(( f'ccore-service-darwin-amd64-{CORE_SERVICE_VERSION}.gz', f'{CORE_SERVICE_BASE_URL}/{CORE_SERVICE_VERSION}/ccore-service-darwin-amd64-{CORE_SERVICE_VERSION}.gz', 'x86_64' )) elif SYSTEM == 'linux': # Linux download_urls.append(( f'mihomo-linux-arm64-{MIHOMO_VERSION}.gz', f'{MIHOMO_BASE_URL}/{MIHOMO_VERSION}/mihomo-linux-arm64-{MIHOMO_VERSION}.gz', 'arm64' )) download_urls.append(( f'mihomo-linux-amd64-{MIHOMO_VERSION}.gz', f'{MIHOMO_BASE_URL}/{MIHOMO_VERSION}/mihomo-linux-amd64-{MIHOMO_VERSION}.gz', 'x86_64' )) download_urls.append(( f'ccore-service-linux-arm64-{CORE_SERVICE_VERSION}.gz', f'{CORE_SERVICE_BASE_URL}/{CORE_SERVICE_VERSION}/ccore-service-linux-arm64-{CORE_SERVICE_VERSION}.gz', 'arm64' )) download_urls.append(( f'ccore-service-linux-amd64-{CORE_SERVICE_VERSION}.gz', f'{CORE_SERVICE_BASE_URL}/{CORE_SERVICE_VERSION}/ccore-service-linux-amd64-{CORE_SERVICE_VERSION}.gz', 'x86_64' )) elif SYSTEM == 'windows': # Windows download_urls.append(( f'mihomo-windows-arm64-{MIHOMO_VERSION}.zip', f'{MIHOMO_BASE_URL}/{MIHOMO_VERSION}/mihomo-windows-arm64-{MIHOMO_VERSION}.zip', 'arm64' )) download_urls.append(( f'mihomo-windows-amd64-{MIHOMO_VERSION}.zip', f'{MIHOMO_BASE_URL}/{MIHOMO_VERSION}/mihomo-windows-amd64-{MIHOMO_VERSION}.zip', 'x86_64' )) download_urls.append(( f'ccore-service-windows-arm64-{CORE_SERVICE_VERSION}.zip', f'{CORE_SERVICE_BASE_URL}/{CORE_SERVICE_VERSION}/ccore-service-windows-arm64-{CORE_SERVICE_VERSION}.zip', 'arm64' )) download_urls.append(( f'ccore-service-windows-amd64-{CORE_SERVICE_VERSION}.zip', f'{CORE_SERVICE_BASE_URL}/{CORE_SERVICE_VERSION}/ccore-service-windows-amd64-{CORE_SERVICE_VERSION}.zip', 'x86_64' )) return download_urls def download_file(url, output_path): """ 下载文件 """ print(f"正在下载 {url} ...") response = requests.get(url, stream=True) if response.status_code == 200: with open(output_path, 'wb') as file: shutil.copyfileobj(response.raw, file) print(f"下载完成: {output_path}") else: print(f"下载失败 {url}, 状态码: {response.status_code}") def extract_gz_file(file_path, output_path): """ 解压 .gz 文件 """ print(f"正在解压 {file_path} ...") with gzip.open(file_path, 'rb') as f_in: with open(output_path, 'wb') as f_out: shutil.copyfileobj(f_in, f_out) print(f"解压到 {output_path}") def extract_zip_file(file_path, output_dir): """ 解压 .zip 文件 """ print(f"正在解压 {file_path} ...") with ZipFile(file_path, 'r') as zip_ref: zip_ref.extractall(output_dir) print(f"解压到 {output_dir}") def merge_binaries(arm_file, x86_file, output_file): """ 使用 lipo 合并 arm64 和 x86_64 的二进制文件 """ print(f"正在合并 {arm_file} 和 {x86_file} 到 {output_file}") subprocess.run(['lipo', '-create', '-output', output_file, arm_file, x86_file], check=True) print(f"成功合并到 {output_file}") def add_executable_permission(file_path): """ 添加可执行权限(适用于 macOS 和 Linux) """ print(f"正在添加可执行权限到 {file_path}") st = os.stat(file_path) os.chmod(file_path, st.st_mode | stat.S_IEXEC) print(f"已添加可执行权限到 {file_path}") def rename_file(original_path, new_name): """ 重命名文件 """ new_path = os.path.join(ASSETS_DIR, new_name) shutil.move(original_path, new_path) print(f"已重命名 {original_path} 为 {new_path}") return new_path def main(): # 获取下载链接和文件名 download_urls = get_download_urls() # 创建临时目录 with tempfile.TemporaryDirectory() as temp_dir: # 存储架构对应的下载路径(仅适用于 macOS 合并) downloads = { 'mihomo': {'arm64': '', 'x86_64': ''}, 'core-service': {'arm64': '', 'x86_64': ''} } for file_name, url, arch in download_urls: # 下载文件 download_path = os.path.join(temp_dir, file_name) download_file(url, download_path) # 确定服务名称 if 'core-service' in file_name: service_name = 'core-service' elif 'mihomo' in file_name: service_name = 'mihomo' else: raise ValueError(f"未知的服务名称: {file_name}") # 构建输出路径 output_file = os.path.join(temp_dir, service_name + '-' + arch) # 解压文件 if file_name.endswith('.gz'): extract_gz_file(download_path, output_file) elif file_name.endswith('.zip'): extract_zip_file(download_path, temp_dir) # 如果是 macOS,记录不同架构的文件路径 if SYSTEM == 'darwin': downloads[service_name][arch] = output_file # 合并 macOS 下的二进制文件或直接重命名 if SYSTEM == 'darwin': for service in ['mihomo', 'core-service']: arm_file = downloads[service]['arm64'] x86_file = downloads[service]['x86_64'] if arm_file and x86_file: merged_output = os.path.join(temp_dir, service) merge_binaries(arm_file, x86_file, merged_output) add_executable_permission(merged_output) # 如果是合并改名,core-{SYSTEM} # service-{SYSTEM} # 其他平台不变 new_name = f"core-{SYSTEM}" if service == 'mihomo' else f"service-{SYSTEM}" rename_file(merged_output, new_name) else: # 对于 Linux 和 Windows,直接重命名最新下载的文件 for service in ['mihomo', 'core-service']: latest_file = max( [f for f in os.listdir(temp_dir) if service in f], key=lambda x: os.path.getmtime(os.path.join(temp_dir, x)) ) new_name = f"core-{SYSTEM}-{platform.machine().lower()}" if service == 'mihomo' else f"service-{SYSTEM}-{platform.machine().lower()}" if SYSTEM == 'windows': new_name += '.exe' rename_file(os.path.join(temp_dir, latest_file), new_name) if SYSTEM == 'linux': add_executable_permission(os.path.join(ASSETS_DIR, new_name)) if __name__ == "__main__": main()