From 2249fe63e1ac1d03320244cd4fa4fc86e6a111b9 Mon Sep 17 00:00:00 2001 From: JGZ_YES Date: Thu, 9 Apr 2026 19:53:24 +0800 Subject: [PATCH] Update scd.py --- scd.py | 245 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 191 insertions(+), 54 deletions(-) diff --git a/scd.py b/scd.py index ab5e0c3..846099b 100644 --- a/scd.py +++ b/scd.py @@ -26,15 +26,129 @@ DEFAULT_MIRROR = "https://scl.ecuil.com/run/plugins/" # 配置文件路径 CONFIG_FILE = os.path.join(os.path.expanduser("~"), ".scd_config.json") +# 多语言支持 +LANGUAGES = { + "en": { + "installing_plugin": "Installing plugin: {}", + "downloading_from": "Downloading from: {}", + "plugin_installed": "Plugin {} installed successfully!", + "install_failed": "Failed to install plugin {}", + "installing_from_file": "Installing plugins from file: {}", + "file_not_found": "File {} not found", + "no_plugins_in_file": "No plugins found in file", + "all_plugins_installed": "All plugins installed!", + "reading_file_failed": "Failed to read file: {}", + "updating_plugin": "Updating plugin: {}", + "updating_scd": "Updating scd...", + "local_version": "Local version: {}", + "remote_version": "Remote version: {}", + "found_new_version": "Found new version, downloading...", + "unsupported_os": "Unsupported operating system", + "update_failed": "Failed to download update", + "scd_updated": "scd updated successfully!", + "run_new_scd": "Please run the new scd{}", + "already_latest": "{} is already up to date", + "listing_local_plugins": "Listing local plugins...", + "installed_plugins": "Installed plugins:", + "no_plugins_installed": "No plugins installed", + "plugins_dir_not_found": "Plugins directory not found", + "listing_web_plugins": "Listing web plugins...", + "fetching_plugins_from": "Fetching plugins from: {}", + "available_plugins": "Available plugins:", + "no_available_plugins": "No available plugins", + "invalid_api_response": "Invalid API response", + "install_required_packages": "Error: Please install required packages: pip install requests", + "fetch_failed": "Failed to fetch plugins list: {}", + "check_network": "Please check your network connection or mirror URL", + "available_mirrors": "Available mirrors:", + "adding_mirror": "Mirror {} added and set as current mirror", + "mirror_exists": "Mirror {} already exists", + "scd_info": "SCL Plugin Downloader (scd)", + "version": "Version: 1.0.0", + "current_mirror": "Current mirror: {}", + "available_mirrors_count": "Available mirrors: {}", + "cpu_cores": "CPU cores: {}", + "download_threads": "Download threads: {}", + "loading_config_failed": "Failed to load config file: {}", + "saving_config_failed": "Failed to save config file: {}", + "downloading_file": "Downloading: {}", + "download_failed": "Failed to download file: {}", + "error": "Error: {}", + "warning_fallback": "Warning: Using fallback download method. Install requests and tqdm for better progress bars.", + "language_set": "Language set to: {}", + "language_not_supported": "Language not supported. Available languages: en, zh", + "setting_language": "Setting language to: {}", + "current_language": "Current language: {}" + }, + "zh": { + "installing_plugin": "正在安装插件: {}", + "downloading_from": "从以下地址下载: {}", + "plugin_installed": "插件 {} 安装成功!", + "install_failed": "安装插件 {} 失败", + "installing_from_file": "从文件安装插件: {}", + "file_not_found": "文件 {} 不存在", + "no_plugins_in_file": "文件中未找到插件", + "all_plugins_installed": "所有插件安装完成!", + "reading_file_failed": "读取文件失败: {}", + "updating_plugin": "正在更新插件: {}", + "updating_scd": "正在更新 scd...", + "local_version": "本地版本: {}", + "remote_version": "远程版本: {}", + "found_new_version": "发现新版本,正在下载...", + "unsupported_os": "不支持的操作系统", + "update_failed": "下载更新失败", + "scd_updated": "scd 更新成功!", + "run_new_scd": "请运行新的 scd{}", + "already_latest": "{} 已是最新版本,无需更新", + "listing_local_plugins": "正在列出本地插件...", + "installed_plugins": "已安装的插件:", + "no_plugins_installed": "没有安装插件", + "plugins_dir_not_found": "未找到插件目录", + "listing_web_plugins": "正在列出网络插件...", + "fetching_plugins_from": "从以下地址获取插件: {}", + "available_plugins": "可用的插件:", + "no_available_plugins": "没有可用的插件", + "invalid_api_response": "API 响应无效", + "install_required_packages": "错误: 请安装必要的包: pip install requests", + "fetch_failed": "获取插件列表失败: {}", + "check_network": "请检查网络连接或镜像 URL", + "available_mirrors": "可用的镜像源:", + "adding_mirror": "镜像 {} 已添加并设为当前镜像", + "mirror_exists": "镜像 {} 已存在", + "scd_info": "SCL 插件下载器 (scd)", + "version": "版本: 1.0.0", + "current_mirror": "当前镜像: {}", + "available_mirrors_count": "可用镜像: {}", + "cpu_cores": "CPU 核心数: {}", + "download_threads": "下载线程数: {}", + "loading_config_failed": "加载配置文件失败: {}", + "saving_config_failed": "保存配置文件失败: {}", + "downloading_file": "下载中: {}", + "download_failed": "下载文件失败: {}", + "error": "错误: {}", + "warning_fallback": "警告: 使用后备下载方法。安装 requests 和 tqdm 以获得更好的进度条。", + "language_set": "语言已设置为: {}", + "language_not_supported": "不支持的语言。可用语言: en, zh", + "setting_language": "正在设置语言为: {}", + "current_language": "当前语言: {}" + } +} + class SCDownloader: def __init__(self): self.config = self.load_config() self.mirrors = self.config.get("mirrors", [DEFAULT_MIRROR]) self.current_mirror = self.config.get("current_mirror", DEFAULT_MIRROR) + self.language = self.config.get("language", "zh") # 默认中文 # 获取 CPU 核心数,用于多线程下载 self.cpu_cores = os.cpu_count() or 4 self.threads = max(1, self.cpu_cores // 2) + def _(self, key, *args): + """获取翻译文本""" + lang = self.language if self.language in LANGUAGES else "zh" + return LANGUAGES[lang].get(key, key).format(*args) + def load_config(self): """加载配置文件""" if os.path.exists(CONFIG_FILE): @@ -42,19 +156,20 @@ class SCDownloader: with open(CONFIG_FILE, "r", encoding="utf-8") as f: return json.load(f) except Exception as e: - print(f"加载配置文件失败: {e}") - return {"mirrors": [DEFAULT_MIRROR], "current_mirror": DEFAULT_MIRROR} + print(self._("loading_config_failed", e)) + return {"mirrors": [DEFAULT_MIRROR], "current_mirror": DEFAULT_MIRROR, "language": "zh"} def save_config(self): """保存配置文件""" self.config["mirrors"] = self.mirrors self.config["current_mirror"] = self.current_mirror + self.config["language"] = self.language try: os.makedirs(os.path.dirname(CONFIG_FILE), exist_ok=True) with open(CONFIG_FILE, "w", encoding="utf-8") as f: json.dump(self.config, f, indent=2) except Exception as e: - print(f"保存配置文件失败: {e}") + print(self._("saving_config_failed", e)) def add_mirror(self, mirror_url): """添加镜像源""" @@ -62,9 +177,19 @@ class SCDownloader: self.mirrors.append(mirror_url) self.current_mirror = mirror_url self.save_config() - print(f"镜像 {mirror_url} 已添加并设为当前镜像") + print(self._("adding_mirror", mirror_url)) else: - print(f"镜像 {mirror_url} 已存在") + print(self._("mirror_exists", mirror_url)) + + def set_language(self, lang): + """设置语言""" + if lang in LANGUAGES: + print(self._("setting_language", lang)) + self.language = lang + self.save_config() + print(self._("language_set", lang)) + else: + print(self._("language_not_supported")) def download_file(self, url, output_path, show_progress=True): """下载文件并显示进度(模范 PIP 风格)""" @@ -95,7 +220,7 @@ class SCDownloader: return True except ImportError: # 如果没有 requests 和 tqdm,使用 urllib 作为后备 - print("警告: 使用后备下载方法。安装 requests 和 tqdm 以获得更好的进度条。") + print(self._("warning_fallback")) def progress_hook(count, block_size, total_size): if total_size > 0: @@ -117,15 +242,15 @@ class SCDownloader: sys.stdout.flush() return True except urllib.error.URLError as e: - print(f"\n下载文件失败: {e}") + print(f"\n{self._('download_failed', e)}") return False except Exception as e: - print(f"\n错误: {e}") + print(f"\n{self._('error', e)}") return False def install_plugin(self, plugin_name): """安装插件""" - print(f"正在安装插件: {plugin_name}") + print(self._("installing_plugin", plugin_name)) # 构建插件下载 URL plugin_url = f"{self.current_mirror}{plugin_name}.py" @@ -135,20 +260,20 @@ class SCDownloader: os.makedirs("plugins", exist_ok=True) # 下载插件 - print(f"从以下地址下载: {plugin_url}") + print(self._("downloading_from", plugin_url)) if self.download_file(plugin_url, plugin_path): - print(f"插件 {plugin_name} 安装成功!") + print(self._("plugin_installed", plugin_name)) return True else: - print(f"安装插件 {plugin_name} 失败") + print(self._("install_failed", plugin_name)) return False def install_from_file(self, file_path): """从文件安装多个插件""" - print(f"从文件安装插件: {file_path}") + print(self._("installing_from_file", file_path)) if not os.path.exists(file_path): - print(f"文件 {file_path} 不存在") + print(self._("file_not_found", file_path)) return False try: @@ -156,7 +281,7 @@ class SCDownloader: plugins = [line.strip() for line in f if line.strip() and not line.strip().startswith("#")] if not plugins: - print("文件中未找到插件") + print(self._("no_plugins_in_file")) return False # 使用线程池下载插件 @@ -168,12 +293,12 @@ class SCDownloader: try: future.result() except Exception as e: - print(f"安装 {plugin} 时出错: {e}") + print(f"{self._('error', e)}") - print("所有插件安装完成!") + print(self._("all_plugins_installed")) return True except Exception as e: - print(f"读取文件失败: {e}") + print(self._("reading_file_failed", e)) return False def get_plugin_version(self, plugin_name): @@ -203,7 +328,7 @@ class SCDownloader: version_data = response.json() return version_data.get("version", "0.0.0") except Exception as e: - print(f"获取远程版本信息失败: {e}") + print(self._("error", e)) return "0.0.0" def compare_versions(self, v1, v2): @@ -250,26 +375,26 @@ class SCDownloader: version_data = response.json() return version_data.get("v", "0.0.0") except Exception as e: - print(f"获取远程版本信息失败: {e}") + print(self._("error", e)) return "0.0.0" def update_plugin(self, plugin_name): """更新插件""" if plugin_name == "scd": # 更新 scd 本身 - print("正在更新 scd...") + print(self._("updating_scd")) # 获取本地版本 local_version = self.get_scd_version() - print(f"本地版本: {local_version}") + print(self._("local_version", local_version)) # 获取远程版本 remote_version = self.get_remote_scd_version() - print(f"远程版本: {remote_version}") + print(self._("remote_version", remote_version)) # 比较版本 if self.compare_versions(local_version, remote_version) < 0: - print("发现新版本,正在下载...") + print(self._("found_new_version")) # 根据操作系统类型选择下载文件 import platform @@ -282,7 +407,7 @@ class SCDownloader: scd_url = "https://scl.ecuil.com/scd" scd_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "scd") else: - print("不支持的操作系统") + print(self._("unsupported_os")) return False # 下载更新 @@ -293,55 +418,55 @@ class SCDownloader: import os os.chmod(scd_path, 0o755) except Exception as e: - print(f"设置可执行权限失败: {e}") + print(self._("error", e)) - print("scd 更新成功!") - print(f"请运行新的 scd{'文件' if system == 'Windows' else '可执行文件'}") + print(self._("scd_updated")) + print(self._("run_new_scd", "文件" if system == "Windows" else "可执行文件")) return True else: - print("下载更新失败") + print(self._("update_failed")) return False else: - print("scd 已是最新版本,无需更新") + print(self._("already_latest", "scd")) return True else: # 更新普通插件 - print(f"正在更新插件: {plugin_name}") + print(self._("updating_plugin", plugin_name)) # 获取本地版本 local_version = self.get_plugin_version(plugin_name) - print(f"本地版本: {local_version}") + print(self._("local_version", local_version)) # 获取远程版本 remote_version = self.get_remote_plugin_version(plugin_name) - print(f"远程版本: {remote_version}") + print(self._("remote_version", remote_version)) # 比较版本 if self.compare_versions(local_version, remote_version) < 0: - print("发现新版本,正在下载...") + print(self._("found_new_version")) return self.install_plugin(plugin_name) else: - print("插件已是最新版本,无需更新") + print(self._("already_latest", f"插件 {plugin_name}")) return True def list_plugins(self, mode="local"): """列出可用插件""" if mode == "local": - print("正在列出本地插件...") + print(self._("listing_local_plugins")) plugins_dir = "plugins" if os.path.exists(plugins_dir): plugins = [f[:-3] for f in os.listdir(plugins_dir) if f.endswith(".py")] if plugins: - print("已安装的插件:") + print(self._("installed_plugins")) for plugin in plugins: print(f" - {plugin}") else: - print("没有安装插件") + print(self._("no_plugins_installed")) else: - print("未找到插件目录") + print(self._("plugins_dir_not_found")) elif mode == "web": - print("正在列出网络插件...") - print(f"从以下地址获取插件: {self.current_mirror}") + print(self._("listing_web_plugins")) + print(self._("fetching_plugins_from", self.current_mirror)) try: # 尝试从 API 获取插件列表 import requests @@ -353,22 +478,22 @@ class SCDownloader: if plugins_data.get("status") == "success" and "plugins" in plugins_data: plugins = plugins_data["plugins"] if plugins: - print("可用的插件:") + print(self._("available_plugins")) for plugin in plugins: print(f" - {plugin}") else: - print("没有可用的插件") + print(self._("no_available_plugins")) else: - print("API 响应无效") + print(self._("invalid_api_response")) except ImportError: - print("错误: 请安装必要的包: pip install requests") + print(self._("install_required_packages")) except Exception as e: - print(f"获取插件列表失败: {e}") - print("请检查网络连接或镜像 URL") + print(self._("fetch_failed", e)) + print(self._("check_network")) def show_mirrors(self): """显示可用镜像源""" - print("可用的镜像源:") + print(self._("available_mirrors")) for i, mirror in enumerate(self.mirrors): marker = "*" if mirror == self.current_mirror else " " print(f"{marker} [{i+1}] {mirror}") @@ -395,12 +520,19 @@ class SCDownloader: else: self.list_plugins() elif args.command == "info": - print("SCL 插件下载器 (scd)") - print(f"版本: 1.0.0") - print(f"当前镜像: {self.current_mirror}") - print(f"可用镜像: {len(self.mirrors)}") - print(f"CPU 核心数: {self.cpu_cores}") - print(f"下载线程数: {self.threads}") + print(self._("scd_info")) + print(self._("version")) + print(self._("current_mirror", self.current_mirror)) + print(self._("available_mirrors_count", len(self.mirrors))) + print(self._("cpu_cores", self.cpu_cores)) + print(self._("download_threads", self.threads)) + print(self._("current_language", self.language)) + elif args.command == "language": + if args.lang: + self.set_language(args.lang) + else: + print(self._("current_language", self.language)) + def main(): parser = argparse.ArgumentParser(description="SCL 插件下载器") @@ -427,6 +559,10 @@ def main(): # info 命令 subparsers.add_parser("info", help="显示 scd 信息") + # language 命令 + language_parser = subparsers.add_parser("language", help="管理语言设置") + language_parser.add_argument("lang", nargs="?", choices=["en", "zh"], help="要设置的语言: en 或 zh") + args = parser.parse_args() # 处理 -t 参数 @@ -440,5 +576,6 @@ def main(): downloader = SCDownloader() downloader.run(args) + if __name__ == "__main__": main()