From da5bff599400e7b533cddca81d439e5057d997c5 Mon Sep 17 00:00:00 2001 From: Pin Studios Date: Thu, 24 Apr 2025 11:20:21 +0800 Subject: [PATCH] Update version to 1.11.01 and enhance localization for OAuth profile selection. Added new features including Arabic language support, machine ID restoration from backup, and improved error handling in the update process. Updated menu options and fixed various issues for a better user experience. --- .env | 4 +- CHANGELOG.md | 10 ++++ locales/en.json | 4 +- locales/zh_cn.json | 8 +-- locales/zh_tw.json | 17 +++++-- logo.py | 2 +- main.py | 123 +++++++++++++++++++++++++++++++++------------ oauth_auth.py | 14 +++--- 8 files changed, 131 insertions(+), 51 deletions(-) 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