download.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. import os
  2. import platform
  3. import requests
  4. import gzip
  5. import shutil
  6. from zipfile import ZipFile
  7. import stat
  8. import argparse
  9. import subprocess
  10. import tempfile
  11. # 定义常量
  12. MIHOMO_BASE_URL = 'https://github.com/MetaCubeX/mihomo/releases/download'
  13. CORE_SERVICE_BASE_URL = 'https://github.com/alroyso/core-service/releases/download'
  14. MIHOMO_VERSION = 'v1.18.8' # 根据实际版本修改
  15. CORE_SERVICE_VERSION = 'v1.0.2'
  16. ASSETS_DIR = './assets/bin'
  17. SYSTEM = platform.system().lower()
  18. # ClashName.platform 和 ClashName.arch 是动态生成的
  19. def get_platform_arch():
  20. return SYSTEM, platform.machine()
  21. # 如果目录不存在,创建下载目录
  22. if not os.path.exists(ASSETS_DIR):
  23. os.makedirs(ASSETS_DIR)
  24. def get_download_urls():
  25. """
  26. 根据系统生成 mihomo 和 core-service 的下载链接,分别下载 arm64 和 x86_64 架构
  27. """
  28. download_urls = []
  29. # 获取 ClashName 的 platform 和 arch
  30. platform_name, arch_name = get_platform_arch()
  31. # 下载 macOS、Linux、Windows 的 arm64 和 x86_64 架构
  32. if SYSTEM == 'darwin':
  33. # macOS
  34. download_urls.append((
  35. f'mihomo-darwin-arm64-{MIHOMO_VERSION}.gz',
  36. f'{MIHOMO_BASE_URL}/{MIHOMO_VERSION}/mihomo-darwin-arm64-{MIHOMO_VERSION}.gz',
  37. 'arm64'
  38. ))
  39. download_urls.append((
  40. f'mihomo-darwin-amd64-{MIHOMO_VERSION}.gz',
  41. f'{MIHOMO_BASE_URL}/{MIHOMO_VERSION}/mihomo-darwin-amd64-{MIHOMO_VERSION}.gz',
  42. 'x86_64'
  43. ))
  44. download_urls.append((
  45. f'ccore-service-darwin-arm64-{CORE_SERVICE_VERSION}.gz',
  46. f'{CORE_SERVICE_BASE_URL}/{CORE_SERVICE_VERSION}/ccore-service-darwin-arm64-{CORE_SERVICE_VERSION}.gz',
  47. 'arm64'
  48. ))
  49. download_urls.append((
  50. f'ccore-service-darwin-amd64-{CORE_SERVICE_VERSION}.gz',
  51. f'{CORE_SERVICE_BASE_URL}/{CORE_SERVICE_VERSION}/ccore-service-darwin-amd64-{CORE_SERVICE_VERSION}.gz',
  52. 'x86_64'
  53. ))
  54. elif SYSTEM == 'linux':
  55. # Linux
  56. download_urls.append((
  57. f'mihomo-linux-arm64-{MIHOMO_VERSION}.gz',
  58. f'{MIHOMO_BASE_URL}/{MIHOMO_VERSION}/mihomo-linux-arm64-{MIHOMO_VERSION}.gz',
  59. 'arm64'
  60. ))
  61. download_urls.append((
  62. f'mihomo-linux-amd64-{MIHOMO_VERSION}.gz',
  63. f'{MIHOMO_BASE_URL}/{MIHOMO_VERSION}/mihomo-linux-amd64-{MIHOMO_VERSION}.gz',
  64. 'x86_64'
  65. ))
  66. download_urls.append((
  67. f'ccore-service-linux-arm64-{CORE_SERVICE_VERSION}.gz',
  68. f'{CORE_SERVICE_BASE_URL}/{CORE_SERVICE_VERSION}/ccore-service-linux-arm64-{CORE_SERVICE_VERSION}.gz',
  69. 'arm64'
  70. ))
  71. download_urls.append((
  72. f'ccore-service-linux-amd64-{CORE_SERVICE_VERSION}.gz',
  73. f'{CORE_SERVICE_BASE_URL}/{CORE_SERVICE_VERSION}/ccore-service-linux-amd64-{CORE_SERVICE_VERSION}.gz',
  74. 'x86_64'
  75. ))
  76. elif SYSTEM == 'windows':
  77. # Windows
  78. download_urls.append((
  79. f'mihomo-windows-arm64-{MIHOMO_VERSION}.zip',
  80. f'{MIHOMO_BASE_URL}/{MIHOMO_VERSION}/mihomo-windows-arm64-{MIHOMO_VERSION}.zip',
  81. 'arm64'
  82. ))
  83. download_urls.append((
  84. f'mihomo-windows-amd64-{MIHOMO_VERSION}.zip',
  85. f'{MIHOMO_BASE_URL}/{MIHOMO_VERSION}/mihomo-windows-amd64-{MIHOMO_VERSION}.zip',
  86. 'x86_64'
  87. ))
  88. download_urls.append((
  89. f'ccore-service-windows-arm64-{CORE_SERVICE_VERSION}.zip',
  90. f'{CORE_SERVICE_BASE_URL}/{CORE_SERVICE_VERSION}/ccore-service-windows-arm64-{CORE_SERVICE_VERSION}.zip',
  91. 'arm64'
  92. ))
  93. download_urls.append((
  94. f'ccore-service-windows-amd64-{CORE_SERVICE_VERSION}.zip',
  95. f'{CORE_SERVICE_BASE_URL}/{CORE_SERVICE_VERSION}/ccore-service-windows-amd64-{CORE_SERVICE_VERSION}.zip',
  96. 'x86_64'
  97. ))
  98. return download_urls
  99. def download_file(url, output_path):
  100. """
  101. 下载文件
  102. """
  103. print(f"正在下载 {url} ...")
  104. response = requests.get(url, stream=True)
  105. if response.status_code == 200:
  106. with open(output_path, 'wb') as file:
  107. shutil.copyfileobj(response.raw, file)
  108. print(f"下载完成: {output_path}")
  109. else:
  110. print(f"下载失败 {url}, 状态码: {response.status_code}")
  111. def extract_gz_file(file_path, output_path):
  112. """
  113. 解压 .gz 文件
  114. """
  115. print(f"正在解压 {file_path} ...")
  116. with gzip.open(file_path, 'rb') as f_in:
  117. with open(output_path, 'wb') as f_out:
  118. shutil.copyfileobj(f_in, f_out)
  119. print(f"解压到 {output_path}")
  120. def extract_zip_file(file_path, output_dir):
  121. """
  122. 解压 .zip 文件
  123. """
  124. print(f"正在解压 {file_path} ...")
  125. with ZipFile(file_path, 'r') as zip_ref:
  126. zip_ref.extractall(output_dir)
  127. print(f"解压到 {output_dir}")
  128. def merge_binaries(arm_file, x86_file, output_file):
  129. """
  130. 使用 lipo 合并 arm64 和 x86_64 的二进制文件
  131. """
  132. print(f"正在合并 {arm_file} 和 {x86_file} 到 {output_file}")
  133. subprocess.run(['lipo', '-create', '-output', output_file, arm_file, x86_file], check=True)
  134. print(f"成功合并到 {output_file}")
  135. def add_executable_permission(file_path):
  136. """
  137. 添加可执行权限(适用于 macOS 和 Linux)
  138. """
  139. print(f"正在添加可执行权限到 {file_path}")
  140. st = os.stat(file_path)
  141. os.chmod(file_path, st.st_mode | stat.S_IEXEC)
  142. print(f"已添加可执行权限到 {file_path}")
  143. def rename_file(original_path, new_name):
  144. """
  145. 重命名文件
  146. """
  147. new_path = os.path.join(ASSETS_DIR, new_name)
  148. shutil.move(original_path, new_path)
  149. print(f"已重命名 {original_path} 为 {new_path}")
  150. return new_path
  151. def main():
  152. # 获取下载链接和文件名
  153. download_urls = get_download_urls()
  154. # 创建临时目录
  155. with tempfile.TemporaryDirectory() as temp_dir:
  156. # 存储架构对应的下载路径(仅适用于 macOS 合并)
  157. downloads = {
  158. 'mihomo': {'arm64': '', 'x86_64': ''},
  159. 'core-service': {'arm64': '', 'x86_64': ''}
  160. }
  161. for file_name, url, arch in download_urls:
  162. # 下载文件
  163. download_path = os.path.join(temp_dir, file_name)
  164. download_file(url, download_path)
  165. # 确定服务名称
  166. if 'core-service' in file_name:
  167. service_name = 'core-service'
  168. elif 'mihomo' in file_name:
  169. service_name = 'mihomo'
  170. else:
  171. raise ValueError(f"未知的服务名称: {file_name}")
  172. # 构建输出路径
  173. output_file = os.path.join(temp_dir, service_name + '-' + arch)
  174. # 解压文件
  175. if file_name.endswith('.gz'):
  176. extract_gz_file(download_path, output_file)
  177. elif file_name.endswith('.zip'):
  178. extract_zip_file(download_path, temp_dir)
  179. # 如果是 macOS,记录不同架构的文件路径
  180. if SYSTEM == 'darwin':
  181. downloads[service_name][arch] = output_file
  182. # 合并 macOS 下的二进制文件或直接重命名
  183. if SYSTEM == 'darwin':
  184. for service in ['mihomo', 'core-service']:
  185. arm_file = downloads[service]['arm64']
  186. x86_file = downloads[service]['x86_64']
  187. if arm_file and x86_file:
  188. merged_output = os.path.join(temp_dir, service)
  189. merge_binaries(arm_file, x86_file, merged_output)
  190. add_executable_permission(merged_output)
  191. # 如果是合并改名,core-{SYSTEM}
  192. # service-{SYSTEM}
  193. # 其他平台不变
  194. new_name = f"core-{SYSTEM}" if service == 'mihomo' else f"service-{SYSTEM}"
  195. rename_file(merged_output, new_name)
  196. else:
  197. # 对于 Linux 和 Windows,直接重命名最新下载的文件
  198. for service in ['mihomo', 'core-service']:
  199. latest_file = max(
  200. [f for f in os.listdir(temp_dir) if service in f],
  201. key=lambda x: os.path.getmtime(os.path.join(temp_dir, x))
  202. )
  203. new_name = f"core-{SYSTEM}-{platform.machine().lower()}" if service == 'mihomo' else f"service-{SYSTEM}-{platform.machine().lower()}"
  204. if SYSTEM == 'windows':
  205. new_name += '.exe'
  206. rename_file(os.path.join(temp_dir, latest_file), new_name)
  207. if SYSTEM == 'linux':
  208. add_executable_permission(os.path.join(ASSETS_DIR, new_name))
  209. if __name__ == "__main__":
  210. main()