import os import shutil import platform import tempfile import glob from colorama import Fore, Style, init import configparser import sys from config import get_config from datetime import datetime # Initialize colorama init() # Define emoji constants EMOJI = { "FILE": "📄", "BACKUP": "💾", "SUCCESS": "✅", "ERROR": "❌", "INFO": "ℹ️", "RESET": "🔄", "WARNING": "⚠️", } def get_user_documents_path(): """Get user Documents folder path""" if sys.platform == "win32": return os.path.join(os.path.expanduser("~"), "Documents") elif sys.platform == "darwin": return os.path.join(os.path.expanduser("~"), "Documents") else: # Linux # Get actual user's home directory sudo_user = os.environ.get('SUDO_USER') if sudo_user: return os.path.join("/home", sudo_user, "Documents") return os.path.join(os.path.expanduser("~"), "Documents") def get_workbench_cursor_path(translator=None) -> str: """Get Cursor workbench.desktop.main.js path""" system = platform.system() # Read configuration config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip") config_file = os.path.join(config_dir, "config.ini") config = configparser.ConfigParser() if os.path.exists(config_file): config.read(config_file) paths_map = { "Darwin": { # macOS "base": "/Applications/Cursor.app/Contents/Resources/app", "main": "out/vs/workbench/workbench.desktop.main.js" }, "Windows": { "main": "out\\vs\\workbench\\workbench.desktop.main.js" }, "Linux": { "bases": ["/opt/Cursor/resources/app", "/usr/share/cursor/resources/app", "/usr/lib/cursor/app/"], "main": "out/vs/workbench/workbench.desktop.main.js" } } if system == "Linux": # Add extracted AppImage with correct usr structure extracted_usr_paths = glob.glob(os.path.expanduser("~/squashfs-root/usr/share/cursor/resources/app")) paths_map["Linux"]["bases"].extend(extracted_usr_paths) if system not in paths_map: raise OSError(translator.get('reset.unsupported_os', system=system) if translator else f"不支持的操作系统: {system}") if system == "Linux": for base in paths_map["Linux"]["bases"]: main_path = os.path.join(base, paths_map["Linux"]["main"]) print(f"{Fore.CYAN}{EMOJI['INFO']} Checking path: {main_path}{Style.RESET_ALL}") if os.path.exists(main_path): return main_path if system == "Windows": base_path = config.get('WindowsPaths', 'cursor_path') elif system == "Darwin": base_path = paths_map[system]["base"] if config.has_section('MacPaths') and config.has_option('MacPaths', 'cursor_path'): base_path = config.get('MacPaths', 'cursor_path') else: # Linux # For Linux, we've already checked all bases in the loop above # If we're here, it means none of the bases worked, so we'll use the first one base_path = paths_map[system]["bases"][0] if config.has_section('LinuxPaths') and config.has_option('LinuxPaths', 'cursor_path'): base_path = config.get('LinuxPaths', 'cursor_path') main_path = os.path.join(base_path, paths_map[system]["main"]) if not os.path.exists(main_path): raise OSError(translator.get('reset.file_not_found', path=main_path) if translator else f"未找到 Cursor main.js 文件: {main_path}") return main_path def modify_workbench_js(file_path: str, translator=None) -> bool: """ Modify file content """ try: # Save original file permissions original_stat = os.stat(file_path) original_mode = original_stat.st_mode original_uid = original_stat.st_uid original_gid = original_stat.st_gid # Create temporary file with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", errors="ignore", delete=False) as tmp_file: # Read original content with open(file_path, "r", encoding="utf-8", errors="ignore") as main_file: content = main_file.read() patterns = { # 通用按钮替换模式 r'B(k,D(Ln,{title:"Upgrade to Pro",size:"small",get codicon(){return A.rocket},get onClick(){return t.pay}}),null)': r'B(k,D(Ln,{title:"yeongpin GitHub",size:"small",get codicon(){return A.github},get onClick(){return function(){window.open("https://github.com/yeongpin/cursor-free-vip","_blank")}}}),null)', # Windows/Linux r'M(x,I(as,{title:"Upgrade to Pro",size:"small",get codicon(){return $.rocket},get onClick(){return t.pay}}),null)': r'M(x,I(as,{title:"yeongpin GitHub",size:"small",get codicon(){return $.github},get onClick(){return function(){window.open("https://github.com/yeongpin/cursor-free-vip","_blank")}}}),null)', # Mac 通用按钮替换模式 r'$(k,E(Ks,{title:"Upgrade to Pro",size:"small",get codicon(){return F.rocket},get onClick(){return t.pay}}),null)': r'$(k,E(Ks,{title:"yeongpin GitHub",size:"small",get codicon(){return F.rocket},get onClick(){return function(){window.open("https://github.com/yeongpin/cursor-free-vip","_blank")}}}),null)', # Badge 替换 r'