diff --git a/.env b/.env index f200b34..c2b10de 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ -version=1.10.05 -VERSION=1.10.05 +version=1.11.01 +VERSION=1.11.01 diff --git a/CHANGELOG.md b/CHANGELOG.md index 2320012..58c3d58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## v1.11.01 +1. Restore: Some Main Code | 恢復一些主程式碼 +2. Add: Arabic language | 增加阿拉伯語 +3. Add: Language configuration saved setting | 增加語言配置保存設定 +4. Add: Restore Machine ID from Backup | 增加從備份恢復機器ID +5. Add: Owned Website Check Version | 增加擁有網站檢查版本 +6. Fix: use cursor_path from config_file | 修復使用 cursor_path 從 config_file +7. Fix: macOS 'bypass_version.py' get product_json_path from config_file | 修復 macOS 'bypass_version.py' 從 config_file 獲取 product_json_path +8. Fix: Some Issues | 修復一些問題 + ## v1.10.05 1. Remove block_domain.txt | 移除 block_domain.txt 2. Original Code In Github , If u afraid of virus, please clone the code and run locally | 原始碼在 Github 上,如果怕病毒,請複製原始碼並在本機運行 diff --git a/locales/en.json b/locales/en.json index d053c2b..ef4711b 100644 --- a/locales/en.json +++ b/locales/en.json @@ -4,8 +4,8 @@ "exit": "Exit Program", "reset": "Reset Machine ID", "register": "Register New Cursor Account", - "register_google": "Register with Google Account", - "register_github": "Register with GitHub Account", + "register_google": "Register with Self Google Account", + "register_github": "Register with Self GitHub Account", "register_manual": "Register Cursor with Custom Email", "quit": "Close Cursor Application", "select_language": "Change Language", diff --git a/locales/zh_cn.json b/locales/zh_cn.json index e778030..d8dddf3 100644 --- a/locales/zh_cn.json +++ b/locales/zh_cn.json @@ -4,8 +4,8 @@ "exit": "退出程序", "reset": "重置机器ID", "register": "注册新的Cursor账户", - "register_google": "使用Google账户注册", - "register_github": "使用GitHub账户注册", + "register_google": "使用自己的Google账户注册", + "register_github": "使用自己的GitHub账户注册", "register_manual": "使用自定义邮箱注册Cursor", "quit": "关闭Cursor应用", "select_language": "更改语言", @@ -627,7 +627,9 @@ "using_configured_browser_path": "使用配置的 {browser} 路径: {path}", "browser_not_found_trying_chrome": "未找到 {browser},尝试使用 Chrome 代替", "found_chrome_at": "找到 Chrome: {path}", - "found_browser_user_data_dir": "找到 {browser} 用户数据目录: {path}" + "found_browser_user_data_dir": "找到 {browser} 用户数据目录: {path}", + "select_profile": "选择要使用的 {browser} 配置文件:", + "profile_list": "可用 {browser} 配置文件:" }, "browser_profile": { "title": "浏览器配置文件选择", diff --git a/locales/zh_tw.json b/locales/zh_tw.json index dfe4d1c..c702a5e 100644 --- a/locales/zh_tw.json +++ b/locales/zh_tw.json @@ -4,8 +4,8 @@ "exit": "退出程式", "reset": "重置機器ID", "register": "註冊新的Cursor帳戶", - "register_google": "使用Google帳戶註冊", - "register_github": "使用GitHub帳戶註冊", + "register_google": "使用自己的Google帳戶註冊", + "register_github": "使用自己的GitHub帳戶註冊", "register_manual": "使用自定義郵箱註冊Cursor", "quit": "關閉Cursor應用", "select_language": "更改語言", @@ -601,7 +601,18 @@ "warning_could_not_kill_existing_browser_processes": "警告: 無法殺死現有瀏覽器進程: {error}", "browser_failed_to_start": "瀏覽器啟動失敗: {error}", "browser_failed": "瀏覽器啟動失敗: {error}", - "browser_failed_to_start_fallback": "瀏覽器啟動失敗: {error}" + "browser_failed_to_start_fallback": "瀏覽器啟動失敗: {error}", + "using_configured_browser_path": "使用配置的 {browser} 路徑: {path}", + "found_browser_user_data_dir": "找到 {browser} 用戶數據目錄: {path}", + "warning_browser_close": "警告:這將關閉所有正在執行的 {browser} 進程", + "killing_browser_processes": "正在關閉 {browser} 進程...", + "profile_selection_error": "配置文件選擇過程中出錯: {error}", + "select_profile": "選擇要使用的 {browser} 配置文件:", + "profile_list": "可用 {browser} 配置文件:", + "no_profiles": "未找到 {browser} 配置文件", + "error_loading": "載入 {browser} 配置文件時出錯:{error}", + "profile_selected": "已選擇配置文件:{profile}", + "invalid_selection": "選擇無效。請重試" }, "chrome_profile": { "title": "Chrome配置檔案選擇", diff --git a/logo.py b/logo.py index 3cc6eb9..1c9123c 100644 --- a/logo.py +++ b/logo.py @@ -83,7 +83,7 @@ muhammedfurkan plamkatawe Lucaszmv """ OTHER_INFO_TEXT = f"""{Fore.YELLOW} Github: https://github.com/yeongpin/cursor-free-vip{Fore.RED} -Press 8 to change language | 按下 8 键切换语言{Style.RESET_ALL}""" +Press 4 to change language | 按下 4 键切换语言{Style.RESET_ALL}""" # center display LOGO and DESCRIPTION CURSOR_LOGO = center_multiline_text(LOGO_TEXT, handle_chinese=False) diff --git a/main.py b/main.py index f7f23e5..9c33a8e 100644 --- a/main.py +++ b/main.py @@ -366,14 +366,18 @@ def print_menu(): 2: f"{Fore.GREEN}2{Style.RESET_ALL}. {EMOJI['SUCCESS']} {translator.get('menu.register_manual')}", 3: f"{Fore.GREEN}3{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.quit')}", 4: f"{Fore.GREEN}4{Style.RESET_ALL}. {EMOJI['LANG']} {translator.get('menu.select_language')}", - 5: f"{Fore.GREEN}5{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.disable_auto_update')}", - 6: f"{Fore.GREEN}6{Style.RESET_ALL}. {EMOJI['RESET']} {translator.get('menu.totally_reset')}", - 7: f"{Fore.GREEN}7{Style.RESET_ALL}. {EMOJI['CONTRIBUTE']} {translator.get('menu.contribute')}", - 8: f"{Fore.GREEN}8{Style.RESET_ALL}. {EMOJI['SETTINGS']} {translator.get('menu.config')}", - 9: f"{Fore.GREEN}9{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.bypass_version_check', fallback='Bypass Cursor Version Check')}", - 10: f"{Fore.GREEN}10{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.check_user_authorized', fallback='Check User Authorized')}", - 11: f"{Fore.GREEN}11{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.bypass_token_limit', fallback='Bypass Token Limit')}", - 12: f"{Fore.GREEN}12{Style.RESET_ALL}. {EMOJI['BACKUP']} {translator.get('menu.restore_machine_id', fallback='Restore Machine ID from Backup')}" + 5: f"{Fore.GREEN}5{Style.RESET_ALL}. {EMOJI['SUN']} {translator.get('menu.register_google')}", + 6: f"{Fore.GREEN}6{Style.RESET_ALL}. {EMOJI['STAR']} {translator.get('menu.register_github')}", + 7: f"{Fore.GREEN}7{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.disable_auto_update')}", + 8: f"{Fore.GREEN}8{Style.RESET_ALL}. {EMOJI['RESET']} {translator.get('menu.totally_reset')}", + 9: f"{Fore.GREEN}9{Style.RESET_ALL}. {EMOJI['CONTRIBUTE']} {translator.get('menu.contribute')}", + 10: f"{Fore.GREEN}10{Style.RESET_ALL}. {EMOJI['SETTINGS']} {translator.get('menu.config')}", + 11: f"{Fore.GREEN}11{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.bypass_version_check')}", + 12: f"{Fore.GREEN}12{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.check_user_authorized')}", + 13: f"{Fore.GREEN}13{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.bypass_token_limit')}", + 14: f"{Fore.GREEN}14{Style.RESET_ALL}. {EMOJI['BACKUP']} {translator.get('menu.restore_machine_id')}", + 15: f"{Fore.GREEN}15{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.delete_google_account')}", + 16: f"{Fore.GREEN}16{Style.RESET_ALL}. {EMOJI['SETTINGS']} {translator.get('menu.select_chrome_profile')}" } # Automatically calculate the number of menu items in the left and right columns @@ -496,31 +500,67 @@ def check_latest_version(): try: print(f"\n{Fore.CYAN}{EMOJI['UPDATE']} {translator.get('updater.checking')}{Style.RESET_ALL}") - # Get latest version from GitHub API with timeout and proper headers + # First try GitHub API headers = { 'Accept': 'application/vnd.github.v3+json', 'User-Agent': 'CursorFreeVIP-Updater' } - response = requests.get( - "https://api.github.com/repos/yeongpin/cursor-free-vip/releases/latest", - headers=headers, - timeout=10 - ) - # Check if rate limit exceeded - if response.status_code == 403 and "rate limit exceeded" in response.text.lower(): - print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('updater.rate_limit_exceeded', fallback='GitHub API rate limit exceeded. Skipping update check.')}{Style.RESET_ALL}") - return + latest_version = None + github_error = None - # Check if response is successful - if response.status_code != 200: - raise Exception(f"GitHub API returned status code {response.status_code}") + # Try GitHub API first + try: + github_response = requests.get( + "https://api.github.com/repos/yeongpin/cursor-free-vip/releases/latest", + headers=headers, + timeout=10 + ) - response_data = response.json() - if "tag_name" not in response_data: - raise Exception("No version tag found in GitHub response") + # Check if rate limit exceeded + if github_response.status_code == 403 and "rate limit exceeded" in github_response.text.lower(): + print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('updater.rate_limit_exceeded', fallback='GitHub API rate limit exceeded. Trying backup API...')}{Style.RESET_ALL}") + raise Exception("Rate limit exceeded") + + # Check if response is successful + if github_response.status_code != 200: + raise Exception(f"GitHub API returned status code {github_response.status_code}") + + github_data = github_response.json() + if "tag_name" not in github_data: + raise Exception("No version tag found in GitHub response") + + latest_version = github_data["tag_name"].lstrip('v') - latest_version = response_data["tag_name"].lstrip('v') + except Exception as e: + github_error = str(e) + print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('updater.github_api_failed', fallback='GitHub API failed, trying backup API...')}{Style.RESET_ALL}") + + # If GitHub API fails, try backup API + try: + backup_headers = { + 'Accept': 'application/json', + 'User-Agent': 'CursorFreeVIP-Updater' + } + backup_response = requests.get( + "https://pinnumber.rr.nu/badges/release/yeongpin/cursor-free-vip", + headers=backup_headers, + timeout=10 + ) + + # Check if response is successful + if backup_response.status_code != 200: + raise Exception(f"Backup API returned status code {backup_response.status_code}") + + backup_data = backup_response.json() + if "message" not in backup_data: + raise Exception("No version tag found in backup API response") + + latest_version = backup_data["message"].lstrip('v') + + except Exception as backup_e: + # If both APIs fail, raise the original GitHub error + raise Exception(f"Both APIs failed. GitHub error: {github_error}, Backup error: {str(backup_e)}") # Validate version format if not latest_version: @@ -670,7 +710,7 @@ def main(): while True: try: - choice_num = 12 + choice_num = 16 choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices=f'0-{choice_num}')}: {Style.RESET_ALL}") match choice: @@ -695,38 +735,55 @@ def main(): print_menu() continue case "5": + from oauth_auth import main as oauth_main + oauth_main('google',translator) + print_menu() + case "6": + from oauth_auth import main as oauth_main + oauth_main('github',translator) + print_menu() + case "7": import disable_auto_update disable_auto_update.run(translator) print_menu() - case "6": + case "8": import totally_reset_cursor totally_reset_cursor.run(translator) # print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.fixed_soon')}{Style.RESET_ALL}") print_menu() - case "7": + case "9": import logo print(logo.CURSOR_CONTRIBUTORS) print_menu() - case "8": + case "10": from config import print_config print_config(get_config(), translator) print_menu() - case "9": + case "11": import bypass_version bypass_version.main(translator) print_menu() - case "10": + case "12": import check_user_authorized check_user_authorized.main(translator) print_menu() - case "11": + case "13": import bypass_token_limit bypass_token_limit.run(translator) print_menu() - case "12": + case "14": import restore_machine_id restore_machine_id.run(translator) print_menu() + case "15": + import delete_cursor_google + delete_cursor_google.main(translator) + print_menu() + case "16": + from oauth_auth import OAuthHandler + oauth = OAuthHandler(translator) + oauth._select_profile() + print_menu() case _: print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}") print_menu() diff --git a/oauth_auth.py b/oauth_auth.py index 4313041..c30c198 100644 --- a/oauth_auth.py +++ b/oauth_auth.py @@ -74,8 +74,8 @@ class OAuthHandler: if self.translator: # 动态使用浏览器类型 - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('browser_profile.select_profile', browser=browser_type_display)}{Style.RESET_ALL}") - print(f"{Fore.CYAN}{self.translator.get('browser_profile.profile_list', browser=browser_type_display)}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.select_profile', browser=browser_type_display)}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{self.translator.get('oauth.profile_list', browser=browser_type_display)}{Style.RESET_ALL}") else: print(f"{Fore.CYAN}{EMOJI['INFO']} Select {browser_type_display} profile to use:{Style.RESET_ALL}") print(f"Available {browser_type_display} profiles:") @@ -125,31 +125,31 @@ class OAuthHandler: self.selected_profile = selected_profile if self.translator: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('browser_profile.profile_selected', profile=selected_profile)}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.profile_selected', profile=selected_profile)}{Style.RESET_ALL}") else: print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Selected profile: {selected_profile}{Style.RESET_ALL}") return True else: if self.translator: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('browser_profile.invalid_selection')}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.invalid_selection')}{Style.RESET_ALL}") else: print(f"{Fore.RED}{EMOJI['ERROR']} Invalid selection. Please try again.{Style.RESET_ALL}") return self._select_profile() except ValueError: if self.translator: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('browser_profile.invalid_selection')}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.invalid_selection')}{Style.RESET_ALL}") else: print(f"{Fore.RED}{EMOJI['ERROR']} Invalid selection. Please try again.{Style.RESET_ALL}") return self._select_profile() else: # No Local State file, use Default profile - print(f"{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('browser_profile.no_profiles', browser=browser_type_display) if self.translator else f'No {browser_type_display} profiles found'}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('oauth.no_profiles', browser=browser_type_display) if self.translator else f'No {browser_type_display} profiles found'}{Style.RESET_ALL}") self.selected_profile = "Default" return True except Exception as e: # Error loading profiles, use Default profile - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('browser_profile.error_loading', error=str(e), browser=browser_type_display) if self.translator else f'Error loading {browser_type_display} profiles: {str(e)}'}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.error_loading', error=str(e), browser=browser_type_display) if self.translator else f'Error loading {browser_type_display} profiles: {str(e)}'}{Style.RESET_ALL}") self.selected_profile = "Default" return True