Compare commits

...

19 Commits

Author SHA1 Message Date
Pin Studios
3200271156 Merge pull request #224 from RenjiYuusei/main
Add Vietnamese Language Support
2025-03-14 12:15:53 +08:00
yeongpin
8401f4718e Update CHANGELOG.md for version 1.7.07
- Add Vietnamese language support and admin privilege management features for Windows executables.
- Implement admin privilege detection and enhance startup process with verification.
- Introduce functions to check and request admin rights when running as a frozen executable.
- Include new admin-related emoji in the EMOJI dictionary and provide fallback for non-Windows platforms.
2025-03-14 12:15:37 +08:00
yeongpin
b761bf0b6d Update localization and versioning for Vietnamese support
- Increment version to 1.7.07 in .env file.
- Add Vietnamese language support in main.py and localization files (vi.json, zh_cn.json, zh_tw.json).
- Translate Chinese language options to English in localization files.
2025-03-14 12:12:58 +08:00
Renji Yuusei
db95689a8e Remove Vietnamese Language Option from Chinese Localization Files
- Updated zh_cn.json and zh_tw.json to remove the Vietnamese language entry while retaining other language options.
2025-03-14 06:54:12 +07:00
Renji Yuusei
652ffc809a Add Vietnamese Language Support
- Update localization files to include Vietnamese language option
2025-03-14 00:25:20 +07:00
Pin Studios
a854969682 Update README.md 2025-03-13 12:09:56 +08:00
Pin Studios
9c5ac85759 Merge pull request #199 from ahmed98Osama/feature/admin-privileges
feat: Add Admin Privilege Management for Windows Executable
2025-03-13 12:08:36 +08:00
Ahemd Farouk
a67264d5c2 refactor: Simplify Admin Privilege Request Logic
- Consolidate admin privilege request logic for Windows by removing redundant checks for frozen executables
2025-03-12 16:51:56 +02:00
Ahemd Farouk
68b1dae466 feat: Add Admin Privilege Management for Windows Executable
- Implement admin privilege detection for Windows platform
- Add functions to check and request admin rights when running as a frozen executable
- Enhance startup process with admin privilege verification
- Add new admin-related emoji to the EMOJI dictionary
- Provide fallback mechanism for non-Windows platforms
2025-03-11 14:56:47 +02:00
yeongpin
0da6f9a1b7 feat: Add Chinese and English Question Issue Templates
- Create bilingual issue templates for discussions and questions
- Add comprehensive sections for platform, version, and problem description
- Include checklist to guide users in providing clear and helpful issue details
- Support both Chinese and English language issue submissions
2025-03-11 12:53:58 +08:00
yeongpin
59fccecb0f feat: Add English Bug Report Issue Template
- Create a new issue template for English-language bug reports
- Mirror the structure of the Chinese bug report template
- Include comprehensive sections for platform, version, and error description
- Add checklist to guide users in providing clear and helpful issue details
2025-03-11 12:47:33 +08:00
yeongpin
1769d245f9 feat: Add Chinese Bug Report Issue Template
- Create a new issue template for Chinese-language bug reports
- Include comprehensive sections for platform, version, and error description
- Add checklist to guide users in providing clear and helpful issue details
- Enhance issue submission process with specific guidelines
2025-03-11 12:45:17 +08:00
yeongpin
b98f094407 refactor: Internationalize and Clean Up Code Comments
- Translate Chinese comments to English across multiple files
- Improve code readability by using consistent, clear comments
- Remove redundant comments and simplify language-specific annotations
- Maintain existing code structure while enhancing internationalization
2025-03-11 12:09:07 +08:00
yeongpin
ff358588bb feat: Refactor Project Structure and Add Configuration Management
- Add `config.py` for centralized configuration management
- Add `utils.py` for cross-platform utility functions
- Remove `browser.py` and `control.py` to simplify project structure
- Update version to 1.7.06
- Modify build specification to reflect new file structure
- Update localization files with new update confirmation messages
- Enhance configuration loading and path detection across different platforms
2025-03-11 11:49:17 +08:00
yeongpin
6ca80ccb10 Merge branch 'main' of https://github.com/yeongpin/cursor-free-vip 2025-03-11 10:12:57 +08:00
yeongpin
2fca5218fb remove md 2025-03-11 10:12:54 +08:00
Pin Studios
71ecf5a201 Update issue templates 2025-03-11 10:12:41 +08:00
Pin Studios
4570b174ab Update issue templates 2025-03-10 18:36:36 +08:00
yeongpin
f708ce443b fix: Correct Syntax in Linux Installation Script
- Fix syntax error in install script's conditional statements
- Remove unnecessary braces and correct shell script syntax
- Ensure proper handling of Linux architecture detection
2025-03-10 17:54:09 +08:00
26 changed files with 1072 additions and 620 deletions

4
.env
View File

@@ -1,2 +1,2 @@
version=1.7.05 version=1.7.07
VERSION=1.7.05 VERSION=1.7.07

View File

@@ -0,0 +1,70 @@
name: ❌ 错误报告 [中文]
description: 创建一个报告以帮助我们改进
title: '[Bug]: '
labels: ['bug']
body:
- type: markdown
attributes:
value: |
感谢您花时间填写此错误报告!
在提交 Issue 前请确保您已经阅读了[Github Issues](https://github.com/yeongpin/cursor-free-vip/issues)
- type: checkboxes
id: checklist
attributes:
label: 提交前检查
description: |
请确保您在提交 Issue 前已经完成了以下所有步骤
options:
- label: 我理解 Issue 是用于反馈和解决问题的,而非吐槽评论区,将尽可能提供更多信息帮助问题解决。
required: true
- label: 我已经查看了置顶 Issue 并搜索了现有的 [开放 Issue](https://github.com/yeongpin/cursor-free-vip/issues)和[已关闭 Issue](https://github.com/yeongpin/cursor-free-vip/issues?q=is%3Aissue%20state%3Aclosed%20),没有找到类似的问题。
required: true
- label: 我填写了简短且清晰明确的标题,以便开发者在翻阅 Issue 列表时能快速确定大致问题。而不是“一个建议”、“卡住了”等。
required: true
- type: dropdown
id: platform
attributes:
label: 平台
description: 您正在使用哪个平台?
options:
- Windows x32
- Windows x64
- macOS Intel
- macOS ARM64
- Linux x64
- Linux ARM64
validations:
required: true
- type: input
id: version
attributes:
label: 版本
description: 您正在运行的 Cursor Free Vip 版本是什么?
placeholder: 例如 v1.0.0
validations:
required: true
- type: textarea
id: description
attributes:
label: 错误描述
description: 描述问题时请尽可能详细
placeholder: 告诉我们发生了什么...
validations:
required: true
- type: textarea
id: logs
attributes:
label: 相关日志输出
description: 请复制并粘贴任何相关的日志输出
render: shell
- type: textarea
id: additional
attributes:
label: 附加信息
description: 任何能让我们对你所遇到的问题有更多了解的东西

75
.github/ISSUE_TEMPLATE/cn_question.yml vendored Normal file
View File

@@ -0,0 +1,75 @@
name: ❓ 讨论 & 提问 (中文)
description: 寻求帮助、讨论问题、提出疑问等...
title: '[讨论]: '
labels: ['question']
body:
- type: markdown
attributes:
value: |
感谢您的提问!请尽可能详细地描述您的问题,这样我们才能更好地帮助您。
- type: checkboxes
id: checklist
attributes:
label: Issue 检查清单
description: |
在提交 Issue 前请确保您已经完成了以下所有步骤
options:
- label: 我理解 Issue 是用于反馈和解决问题的,而非吐槽评论区,将尽可能提供更多信息帮助问题解决。
required: true
- label: 我确认自己需要的是提出问题并且讨论问题,而不是 Bug 反馈或需求建议。
required: true
- label: 我已阅读 [Github Issues](https://github.com/yeongpin/cursor-free-vip/issues) 并搜索了现有的 [开放 Issue](https://github.com/yeongpin/cursor-free-vip/issues) 和 [已关闭 Issue](https://github.com/yeongpin/cursor-free-vip/issues?q=is%3Aissue%20state%3Aclosed%20),没有找到类似的问题。
required: true
- type: dropdown
id: platform
attributes:
label: 平台
description: 您正在使用哪个平台?
options:
- Windows x32
- Windows x64
- macOS Intel
- macOS ARM64
- Linux x64
- Linux ARM64
validations:
required: true
- type: input
id: version
attributes:
label: 版本
description: 您正在运行的 Cursor Free Vip 版本是什么?
placeholder: 例如 v1.0.0
validations:
required: true
- type: textarea
id: question
attributes:
label: 您的问题
description: 请详细描述您的问题
placeholder: 请尽可能清楚地说明您的问题...
validations:
required: true
- type: textarea
id: additional
attributes:
label: 补充信息
description: 任何其他相关的信息、截图或代码示例
render: shell
- type: dropdown
id: priority
attributes:
label: 优先级
description: 这个问题对您来说有多紧急?
options:
- 低 (有空再看)
- 中 (希望尽快得到答复)
- 高 (阻碍工作进行)
validations:
required: true

View File

@@ -0,0 +1,70 @@
name: ❌ Bug Report [English]
description: Create a report to help us improve
title: '[Bug]: '
labels: ['bug']
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to fill out this bug report!
Before submitting this issue, please ensure that you have read the [github issues](https://github.com/yeongpin/cursor-free-vip/issues)
- type: checkboxes
id: checklist
attributes:
label: Commit before submitting
description: |
Please ensure that you have completed all of the following steps before submitting an issue
options:
- label: I understand that Issues are used to provide feedback and solve problems, not to complain in the comments section, and will provide more information to help solve the problem.
required: true
- label: I have checked the top Issue and searched for existing [open issues](https://github.com/yeongpin/cursor-free-vip/issues) and [closed issues](https://github.com/yeongpin/cursor-free-vip/issues?q=is%3Aissue%20state%3Aclosed%20), and found no similar issues.
required: true
- label: I have filled out a short and clear title, so that developers can quickly determine the general problem when browsing the Issue list. Not "a suggestion", "stuck", etc.
required: true
- type: dropdown
id: platform
attributes:
label: Platform
description: Which platform are you using?
options:
- Windows x32
- Windows x64
- macOS Intel
- macOS ARM64
- Linux x64
- Linux ARM64
validations:
required: true
- type: input
id: version
attributes:
label: Version
description: What version of Cursor Free Vip are you running?
placeholder: For example v1.0.0
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
description: Please describe the problem as detailed as possible
placeholder: Tell us what happened...
validations:
required: true
- type: textarea
id: logs
attributes:
label: Related log output
description: Please copy and paste any related log output
render: shell
- type: textarea
id: additional
attributes:
label: Additional information
description: Anything that might help us understand the problem better

75
.github/ISSUE_TEMPLATE/en_question.yml vendored Normal file
View File

@@ -0,0 +1,75 @@
name: ❓ Discussion & Question [English]
description: Seeking help, discussing problems, asking questions, etc.
title: '[Discussion]: '
labels: ['question']
body:
- type: markdown
attributes:
value: |
Thank you for your question! Please describe your problem as detailed as possible so we can help you better.
- type: checkboxes
id: checklist
attributes:
label: Issue Checklist
description: |
Please ensure that you have completed all of the following steps before submitting an issue
options:
- label: I understand that Issues are used to provide feedback and solve problems, not to complain in the comments section, and will provide more information to help solve the problem.
required: true
- label: I confirm that I need to raise questions and discuss problems, not Bug feedback or demand suggestions.
required: true
- label: I have read [Github Issues](https://github.com/yeongpin/cursor-free-vip/issues) and searched for existing [open issues](https://github.com/yeongpin/cursor-free-vip/issues) and [closed issues](https://github.com/yeongpin/cursor-free-vip/issues?q=is%3Aissue%20state%3Aclosed%20), and found no similar issues.
required: true
- type: dropdown
id: platform
attributes:
label: Platform
description: Which platform are you using?
options:
- Windows x32
- Windows x64
- macOS Intel
- macOS ARM64
- Linux x64
- Linux ARM64
validations:
required: true
- type: input
id: version
attributes:
label: Version
description: What version of Cursor Free Vip are you running?
placeholder: For example v1.0.0
validations:
required: true
- type: textarea
id: question
attributes:
label: Your question
description: Please describe your problem as detailed as possible
placeholder: Please explain your question as clearly as possible...
validations:
required: true
- type: textarea
id: additional
attributes:
label: Additional information
description: Any other related information, screenshots, or code examples
render: shell
- type: dropdown
id: priority
attributes:
label: Priority
description: How urgent is this issue for you?
options:
- Low (I'll look at it when I have time)
- Medium (I hope to get an answer soon)
- High (It blocks my work)
validations:
required: true

View File

@@ -6,7 +6,7 @@ on:
version: version:
description: 'Version number (e.g. 1.0.9)' description: 'Version number (e.g. 1.0.9)'
required: true required: true
default: '1.7.05' default: '1.7.06'
permissions: permissions:
contents: write contents: write

View File

@@ -1,5 +1,29 @@
# Change Log # Change Log
## v1.7.07
1. Add: Vietnamese Language | 增加越南語言
2. Add: Admin Privilege Management for Windows Executable | 增加Windows可執行文件管理員權限
3. Implement admin privilege detection for Windows platform | 實現Windows平台管理員權限檢測
4. Add functions to check and request admin rights when running as a frozen executable | 增加檢查和請求管理員權限的功能
5. Enhance startup process with admin privilege verification | 增強啟動過程中的管理員權限驗證
6. Add new admin-related emoji to the EMOJI dictionary | 增加新的管理員相關表情符號到EMOJI字典
7. Provide fallback mechanism for non-Windows platforms (macos and linux ) | 提供非Windows平台macos和linux的回退機制
These changes make the application more user-friendly by only requesting admin privileges when necessary (when running as an executable). | 這些改進使應用程序更易於使用,只在必要時(當作為可執行文件運行時)請求管理員權限。
## v1.7.06
1. Add: Update Confirm | 增加更新確認
2. Add: Update Skipped | 增加更新跳過
3. Add: Invalid Choice | 增加無效選擇
4. Fix: Cursor Path | 修復Cursor路徑
5. Fix: Path Encoding | 修復路徑編碼
6. Fix: Getting Verification Code | 修復獲取驗證碼
7. Fix: Setting Password | 修復設置密碼
8. Fix: Disable Auto Update | 修復禁用自動更新
9. Add Config.py | 增加Config.py
10. Add utils.py | 增加utils.py
11. Rebuild some logic | 重新構建一些邏輯
## v1.7.05 ## v1.7.05
1. Fix: Cursor Version Check | 修復Cursor版本檢查 1. Fix: Cursor Version Check | 修復Cursor版本檢查
2. Fix: Small Problem | 修復一些小問題 2. Fix: Small Problem | 修復一些小問題

View File

@@ -12,7 +12,7 @@
[![Download](https://img.shields.io/github/downloads/yeongpin/cursor-free-vip/total?style=flat-square&logo=github&color=52c41a)](https://github.com/yeongpin/cursor-free-vip/releases/latest) [![Download](https://img.shields.io/github/downloads/yeongpin/cursor-free-vip/total?style=flat-square&logo=github&color=52c41a)](https://github.com/yeongpin/cursor-free-vip/releases/latest)
</p> </p>
<h4>Support Latest 0.46.10 Version | 支持最新0.46.10版本</h4> <h4>Support Latest 0.47.x Version | 支持最新0.47.x版本</h4>
This is a tool to automatically register , support Windows and macOS systems, complete Auth verification, and reset Cursor's configuration. This is a tool to automatically register , support Windows and macOS systems, complete Auth verification, and reset Cursor's configuration.

View File

@@ -1,95 +0,0 @@
from DrissionPage import ChromiumOptions, ChromiumPage
import sys
import os
import logging
import random
class BrowserManager:
def __init__(self, noheader=False):
self.browser = None
self.noheader = noheader
def init_browser(self):
"""初始化浏览器"""
co = self._get_browser_options()
# 如果设置了 noheader添加相应的参数
if self.noheader:
co.set_argument('--headless=new')
self.browser = ChromiumPage(co)
return self.browser
def _get_browser_options(self):
"""获取浏览器配置"""
co = ChromiumOptions()
try:
extension_path = self._get_extension_path()
co.add_extension(extension_path)
co.set_argument("--allow-extensions-in-incognito")
extension_block_path = self.get_extension_block()
co.add_extension(extension_block_path)
co.set_argument("--allow-extensions-in-incognito")
except FileNotFoundError as e:
logging.warning(f"警告: {e}")
# 设置更真实的用户代理
co.set_user_agent(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
)
# 基本设置
co.set_pref("credentials_enable_service", False)
# 随机端口
co.auto_port()
# 系统特定设置
if sys.platform == "darwin": # macOS
co.set_argument("--disable-gpu")
co.set_argument("--no-sandbox")
elif sys.platform == "win32": # Windows
co.set_argument("--disable-software-rasterizer")
# 设置窗口大小
window_width = random.randint(1024, 1920)
window_height = random.randint(768, 1080)
co.set_argument(f"--window-size={window_width},{window_height}")
return co
def _get_extension_path(self):
"""获取插件路径"""
root_dir = os.getcwd()
extension_path = os.path.join(root_dir, "turnstilePatch")
if hasattr(sys, "_MEIPASS"):
extension_path = os.path.join(sys._MEIPASS, "turnstilePatch")
if not os.path.exists(extension_path):
raise FileNotFoundError(f"插件不存在: {extension_path}")
return extension_path
def get_extension_block(self):
"""获取插件路径"""
root_dir = os.getcwd()
extension_path = os.path.join(root_dir, "PBlock")
if hasattr(sys, "_MEIPASS"):
extension_path = os.path.join(sys._MEIPASS, "PBlock")
if not os.path.exists(extension_path):
raise FileNotFoundError(f"插件不存在: {extension_path}")
return extension_path
def quit(self):
"""关闭浏览器"""
if self.browser:
try:
self.browser.quit()
except:
pass

View File

@@ -29,15 +29,19 @@ a = Analysis(
('cursor_auth.py', '.'), ('cursor_auth.py', '.'),
('reset_machine_manual.py', '.'), ('reset_machine_manual.py', '.'),
('cursor_register.py', '.'), ('cursor_register.py', '.'),
('browser.py', '.'), ('new_signup.py', '.'),
('control.py', '.'), ('new_tempemail.py', '.'),
('quit_cursor.py', '.'),
('cursor_register_manual.py', '.'),
('.env', '.') ('.env', '.')
], ],
hiddenimports=[ hiddenimports=[
'cursor_auth', 'cursor_auth',
'reset_machine_manual', 'reset_machine_manual',
'browser', 'new_signup',
'control' 'new_tempemail',
'quit_cursor',
'cursor_register_manual'
], ],
hookspath=[], hookspath=[],
hooksconfig={}, hooksconfig={},

117
config.py Normal file
View File

@@ -0,0 +1,117 @@
import os
import sys
import configparser
from colorama import Fore, Style
from utils import get_user_documents_path, get_default_chrome_path, get_linux_cursor_path
def setup_config(translator=None):
"""Setup configuration file and return config object"""
try:
config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip")
config_file = os.path.join(config_dir, "config.ini")
os.makedirs(config_dir, exist_ok=True)
config = configparser.ConfigParser()
# Default configuration
default_config = {
'Chrome': {
'chromepath': get_default_chrome_path()
},
'Turnstile': {
'handle_turnstile_time': '2',
'handle_turnstile_random_time': '1-3'
},
'Timing': {
'min_random_time': '0.1',
'max_random_time': '0.8',
'page_load_wait': '0.1-0.8',
'input_wait': '0.3-0.8',
'submit_wait': '0.5-1.5',
'verification_code_input': '0.1-0.3',
'verification_success_wait': '2-3',
'verification_retry_wait': '2-3',
'email_check_initial_wait': '4-6',
'email_refresh_wait': '2-4',
'settings_page_load_wait': '1-2',
'failed_retry_time': '0.5-1',
'retry_interval': '8-12',
'max_timeout': '160'
}
}
# Add system-specific path configuration
if sys.platform == "win32":
appdata = os.getenv("APPDATA")
localappdata = os.getenv("LOCALAPPDATA", "")
default_config['WindowsPaths'] = {
'storage_path': os.path.join(appdata, "Cursor", "User", "globalStorage", "storage.json"),
'sqlite_path': os.path.join(appdata, "Cursor", "User", "globalStorage", "state.vscdb"),
'machine_id_path': os.path.join(appdata, "Cursor", "machineId"),
'cursor_path': os.path.join(localappdata, "Programs", "Cursor", "resources", "app"),
'updater_path': os.path.join(localappdata, "cursor-updater")
}
elif sys.platform == "darwin":
default_config['MacPaths'] = {
'storage_path': os.path.abspath(os.path.expanduser("~/Library/Application Support/Cursor/User/globalStorage/storage.json")),
'sqlite_path': os.path.abspath(os.path.expanduser("~/Library/Application Support/Cursor/User/globalStorage/state.vscdb")),
'machine_id_path': os.path.expanduser("~/Library/Application Support/Cursor/machineId"),
'cursor_path': "/Applications/Cursor.app/Contents/Resources/app",
'updater_path': os.path.expanduser("~/Library/Application Support/cursor-updater")
}
elif sys.platform == "linux":
sudo_user = os.environ.get('SUDO_USER')
actual_home = f"/home/{sudo_user}" if sudo_user else os.path.expanduser("~")
default_config['LinuxPaths'] = {
'storage_path': os.path.abspath(os.path.join(actual_home, ".config/Cursor/User/globalStorage/storage.json")),
'sqlite_path': os.path.abspath(os.path.join(actual_home, ".config/Cursor/User/globalStorage/state.vscdb")),
'machine_id_path': os.path.expanduser("~/.config/Cursor/machineId"),
'cursor_path': get_linux_cursor_path(),
'updater_path': os.path.expanduser("~/.config/cursor-updater")
}
# Read existing configuration and merge
if os.path.exists(config_file):
config.read(config_file, encoding='utf-8')
config_modified = False
for section, options in default_config.items():
if not config.has_section(section):
config.add_section(section)
config_modified = True
for option, value in options.items():
if not config.has_option(section, option):
config.set(section, option, str(value))
config_modified = True
if translator:
print(f"{Fore.YELLOW} {translator.get('register.config_option_added', option=f'{section}.{option}')}{Style.RESET_ALL}")
if config_modified:
with open(config_file, 'w', encoding='utf-8') as f:
config.write(f)
if translator:
print(f"{Fore.GREEN}{translator.get('register.config_updated')}{Style.RESET_ALL}")
else:
for section, options in default_config.items():
config.add_section(section)
for option, value in options.items():
config.set(section, option, str(value))
with open(config_file, 'w', encoding='utf-8') as f:
config.write(f)
if translator:
print(f"{Fore.GREEN}{translator.get('register.config_created')}: {config_file}{Style.RESET_ALL}")
return config
except Exception as e:
if translator:
print(f"{Fore.RED}{translator.get('register.config_setup_error', error=str(e))}{Style.RESET_ALL}")
else:
print(f"{Fore.RED}❌ Error setting up config: {e}{Style.RESET_ALL}")
return None
def get_config(translator=None):
"""Get existing config or create new one"""
return setup_config(translator)

View File

@@ -1,181 +0,0 @@
import time
import random
import os
from colorama import Fore, Style, init
# 初始化colorama
init()
# 定义emoji常量
EMOJI = {
'MAIL': '📧',
'REFRESH': '🔄',
'SUCCESS': '',
'ERROR': '',
'INFO': '',
'CODE': '📱'
}
class BrowserControl:
def __init__(self, browser, translator=None):
self.browser = browser
self.translator = translator # 保存translator
self.sign_up_url = "https://authenticator.cursor.sh/sign-up"
self.current_tab = None # 当前标签页
self.signup_tab = None # 注册标签页
self.email_tab = None # 邮箱标签页
def create_new_tab(self):
"""创建新标签页"""
try:
# 保存当前标签页
self.current_tab = self.browser
# 创建新的浏览器实例
from browser import BrowserManager
browser_manager = BrowserManager()
new_browser = browser_manager.init_browser()
# 保存新标签页
self.signup_tab = new_browser
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.create_new_tab_success')}{Style.RESET_ALL}")
return new_browser
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.create_new_tab_failed', error=str(e))}{Style.RESET_ALL}")
return None
def fill_verification_code(self, code):
"""填写验证码"""
try:
if not code or len(code) != 6:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.verification_code_format_error')}{Style.RESET_ALL}")
return False
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('control.fill_verification_code')}...{Style.RESET_ALL}")
# 记住当前标签页(邮箱页面)
email_tab = self.browser
# 切换回注册页面标签
self.switch_to_tab(self.signup_tab)
time.sleep(1)
# 输入验证码
for digit in code:
self.browser.actions.input(digit)
time.sleep(random.uniform(0.1, 0.3))
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.verification_code_filled')}{Style.RESET_ALL}")
# 等待页面加载和登录完成
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('control.wait_for_login')}...{Style.RESET_ALL}")
time.sleep(5)
# 先访问登录页面确保登录状态
login_url = "https://authenticator.cursor.sh"
self.browser.get(login_url)
time.sleep(3) # 增加等待时间
# 获取cookies第一次尝试
token = self.get_cursor_session_token()
if not token:
print(f"{Fore.YELLOW}{EMOJI['ERROR']} {self.translator.get('control.get_token_failed')}...{Style.RESET_ALL}")
time.sleep(3)
token = self.get_cursor_session_token()
if token:
self.save_token_to_file(token)
# 获取到token后再访问设置页面
settings_url = "https://www.cursor.com/settings"
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('control.get_account_info')}...{Style.RESET_ALL}")
self.browser.get(settings_url)
time.sleep(2)
# 获取账户额度信息
try:
usage_selector = (
"css:div.col-span-2 > div > div > div > div > "
"div:nth-child(1) > div.flex.items-center.justify-between.gap-2 > "
"span.font-mono.text-sm\\/\\[0\\.875rem\\]"
)
usage_ele = self.browser.ele(usage_selector)
if usage_ele:
usage_info = usage_ele.text
total_usage = usage_info.split("/")[-1].strip()
print(f"{Fore.GREEN}{EMOJI['INFO']} {self.translator.get('control.account_usage_limit')}: {total_usage}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.get_account_usage_failed', error=str(e))}{Style.RESET_ALL}")
# 切换回邮箱页面
self.switch_to_tab(email_tab)
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.fill_verification_code_failed', error=str(e))}{Style.RESET_ALL}")
return False
def check_and_click_turnstile(self):
"""检查并点击 Turnstile 验证框"""
try:
# 等待验证框出现
time.sleep(1)
# 查找验证框
verify_checkbox = self.browser.ele('xpath://label[contains(@class, "cb-lb")]//input[@type="checkbox"]')
if verify_checkbox:
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('control.find_turnstile_verification_box')}...{Style.RESET_ALL}")
verify_checkbox.click()
time.sleep(2) # 等待验证完成
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.clicked_turnstile_verification_box')}{Style.RESET_ALL}")
return True
return False
except Exception as e:
print(f"{Fore.YELLOW}{EMOJI['ERROR']} {self.translator.get('control.check_and_click_turnstile_failed', error=str(e))}{Style.RESET_ALL}")
return False
def get_cursor_session_token(self, max_attempts=3, retry_interval=2):
"""获取Cursor会话token"""
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('control.get_cursor_session_token')}...{Style.RESET_ALL}")
attempts = 0
while attempts < max_attempts:
try:
# 直接从浏览器对象获取cookies
all_cookies = self.browser.get_cookies()
# 遍历查找目标cookie
for cookie in all_cookies:
if cookie.get("name") == "WorkosCursorSessionToken":
token = cookie["value"].split("%3A%3A")[1]
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.get_cursor_session_token_success')}: {token}{Style.RESET_ALL}")
return token
attempts += 1
if attempts < max_attempts:
print(f"{Fore.YELLOW}{EMOJI['ERROR']} {self.translator.get('control.get_cursor_session_token_failed', attempts=attempts, retry_interval=retry_interval)}...{Style.RESET_ALL}")
time.sleep(retry_interval)
else:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.reach_max_attempts', max_attempts=max_attempts)}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.get_cookie_failed', error=str(e))}{Style.RESET_ALL}")
attempts += 1
if attempts < max_attempts:
print(f"{Fore.YELLOW}{EMOJI['ERROR']} {self.translator.get('control.will_retry_in', retry_interval=retry_interval)}...{Style.RESET_ALL}")
time.sleep(retry_interval)
return None
def save_token_to_file(self, token):
"""保存token到文件"""
try:
with open('cursor_tokens.txt', 'a', encoding='utf-8') as f:
f.write(f"Token: {token}\n")
f.write("-" * 50 + "\n")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.token_saved_to_file')}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.save_token_failed', error=str(e))}{Style.RESET_ALL}")

View File

@@ -2,11 +2,12 @@ import sqlite3
import os import os
import sys import sys
from colorama import Fore, Style, init from colorama import Fore, Style, init
from config import get_config
# 初始化colorama # Initialize colorama
init() init()
# 定义emoji和颜色常量 # Define emoji and color constants
EMOJI = { EMOJI = {
'DB': '🗄️', 'DB': '🗄️',
'UPDATE': '🔄', 'UPDATE': '🔄',
@@ -21,29 +22,48 @@ EMOJI = {
class CursorAuth: class CursorAuth:
def __init__(self, translator=None): def __init__(self, translator=None):
self.translator = translator self.translator = translator
# 判断操作系统
if sys.platform == "win32": # Windows # Get configuration
self.db_path = os.path.join( config = get_config(translator)
os.getenv("APPDATA"), "Cursor", "User", "globalStorage", "state.vscdb" if not config:
) print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.config_error') if self.translator else 'Failed to load configuration'}{Style.RESET_ALL}")
elif sys.platform == 'linux': sys.exit(1)
self.db_path = os.path.expanduser(
"~/.config/Cursor/User/globalStorage/state.vscdb" # Get path based on operating system
) try:
elif sys.platform == 'darwin': # macOS if sys.platform == "win32": # Windows
self.db_path = os.path.expanduser( if not config.has_section('WindowsPaths'):
"~/Library/Application Support/Cursor/User/globalStorage/state.vscdb" raise ValueError("Windows paths not configured")
) self.db_path = config.get('WindowsPaths', 'sqlite_path')
else:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.unsupported_platform')}{Style.RESET_ALL}") elif sys.platform == 'linux': # Linux
if not config.has_section('LinuxPaths'):
raise ValueError("Linux paths not configured")
self.db_path = config.get('LinuxPaths', 'sqlite_path')
elif sys.platform == 'darwin': # macOS
if not config.has_section('MacPaths'):
raise ValueError("macOS paths not configured")
self.db_path = config.get('MacPaths', 'sqlite_path')
else:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.unsupported_platform') if self.translator else 'Unsupported platform'}{Style.RESET_ALL}")
sys.exit(1)
# Verify if the path exists
if not os.path.exists(os.path.dirname(self.db_path)):
raise FileNotFoundError(f"Database directory not found: {os.path.dirname(self.db_path)}")
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.path_error', error=str(e)) if self.translator else f'Error getting database path: {str(e)}'}{Style.RESET_ALL}")
sys.exit(1) sys.exit(1)
# 检查数据库文件是否存在 # Check if the database file exists
if not os.path.exists(self.db_path): if not os.path.exists(self.db_path):
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.db_not_found', path=self.db_path)}{Style.RESET_ALL}") print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.db_not_found', path=self.db_path)}{Style.RESET_ALL}")
return return
# 检查文件权限 # Check file permissions
if not os.access(self.db_path, os.R_OK | os.W_OK): if not os.access(self.db_path, os.R_OK | os.W_OK):
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.db_permission_error')}{Style.RESET_ALL}") print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.db_permission_error')}{Style.RESET_ALL}")
return return
@@ -58,12 +78,12 @@ class CursorAuth:
def update_auth(self, email=None, access_token=None, refresh_token=None): def update_auth(self, email=None, access_token=None, refresh_token=None):
conn = None conn = None
try: try:
# 确保目录存在并设置正确权限 # Ensure the directory exists and set the correct permissions
db_dir = os.path.dirname(self.db_path) db_dir = os.path.dirname(self.db_path)
if not os.path.exists(db_dir): if not os.path.exists(db_dir):
os.makedirs(db_dir, mode=0o755, exist_ok=True) os.makedirs(db_dir, mode=0o755, exist_ok=True)
# 如果数据库文件不存在,创建一个新的 # If the database file does not exist, create a new one
if not os.path.exists(self.db_path): if not os.path.exists(self.db_path):
conn = sqlite3.connect(self.db_path) conn = sqlite3.connect(self.db_path)
cursor = conn.cursor() cursor = conn.cursor()
@@ -78,17 +98,17 @@ class CursorAuth:
os.chmod(self.db_path, 0o644) os.chmod(self.db_path, 0o644)
conn.close() conn.close()
# 重新连接数据库 # Reconnect to the database
conn = sqlite3.connect(self.db_path) conn = sqlite3.connect(self.db_path)
print(f"{EMOJI['INFO']} {Fore.GREEN} {self.translator.get('auth.connected_to_database')}{Style.RESET_ALL}") print(f"{EMOJI['INFO']} {Fore.GREEN} {self.translator.get('auth.connected_to_database')}{Style.RESET_ALL}")
cursor = conn.cursor() cursor = conn.cursor()
# 增加超时和其他优化设置 # Add timeout and other optimization settings
conn.execute("PRAGMA busy_timeout = 5000") conn.execute("PRAGMA busy_timeout = 5000")
conn.execute("PRAGMA journal_mode = WAL") conn.execute("PRAGMA journal_mode = WAL")
conn.execute("PRAGMA synchronous = NORMAL") conn.execute("PRAGMA synchronous = NORMAL")
# 设置要更新的键值对 # Set the key-value pairs to update
updates = [] updates = []
updates.append(("cursorAuth/cachedSignUpType", "Auth_0")) updates.append(("cursorAuth/cachedSignUpType", "Auth_0"))
@@ -101,11 +121,11 @@ class CursorAuth:
updates.append(("cursorAuth/refreshToken", refresh_token)) updates.append(("cursorAuth/refreshToken", refresh_token))
# 使用事务来确保数据完整性 # Use transactions to ensure data integrity
cursor.execute("BEGIN TRANSACTION") cursor.execute("BEGIN TRANSACTION")
try: try:
for key, value in updates: for key, value in updates:
# 检查键是否存在 # Check if the key exists
cursor.execute("SELECT COUNT(*) FROM ItemTable WHERE key = ?", (key,)) cursor.execute("SELECT COUNT(*) FROM ItemTable WHERE key = ?", (key,))
if cursor.fetchone()[0] == 0: if cursor.fetchone()[0] == 0:
cursor.execute(""" cursor.execute("""

View File

@@ -2,8 +2,6 @@ import os
from colorama import Fore, Style, init from colorama import Fore, Style, init
import time import time
import random import random
from browser import BrowserManager
from control import BrowserControl
from cursor_auth import CursorAuth from cursor_auth import CursorAuth
from reset_machine_manual import MachineIDResetter from reset_machine_manual import MachineIDResetter
@@ -35,7 +33,6 @@ class CursorRegistration:
self.translator = translator self.translator = translator
# Set to display mode # Set to display mode
os.environ['BROWSER_HEADLESS'] = 'False' os.environ['BROWSER_HEADLESS'] = 'False'
self.browser_manager = BrowserManager()
self.browser = None self.browser = None
self.controller = None self.controller = None
self.mail_url = "https://yopmail.com/zh/email-generator" self.mail_url = "https://yopmail.com/zh/email-generator"
@@ -45,7 +42,7 @@ class CursorRegistration:
self.signup_tab = None self.signup_tab = None
self.email_tab = None self.email_tab = None
# 账号信息 # Account information
self.password = self._generate_password() self.password = self._generate_password()
# Generate first name and last name separately # Generate first name and last name separately
first_name = random.choice([ first_name = random.choice([
@@ -199,17 +196,17 @@ class CursorRegistration:
def _save_account_info(self, token, total_usage): def _save_account_info(self, token, total_usage):
"""Save Account Information to File""" """Save Account Information to File"""
try: try:
# 先更新认证信息 # Update authentication information first
print(f"{Fore.CYAN}{EMOJI['KEY']} {self.translator.get('register.update_cursor_auth_info')}...{Style.RESET_ALL}") print(f"{Fore.CYAN}{EMOJI['KEY']} {self.translator.get('register.update_cursor_auth_info')}...{Style.RESET_ALL}")
if self.update_cursor_auth(email=self.email_address, access_token=token, refresh_token=token): if self.update_cursor_auth(email=self.email_address, access_token=token, refresh_token=token):
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.cursor_auth_info_updated')}...{Style.RESET_ALL}") print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.cursor_auth_info_updated')}...{Style.RESET_ALL}")
else: else:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.cursor_auth_info_update_failed')}...{Style.RESET_ALL}") print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.cursor_auth_info_update_failed')}...{Style.RESET_ALL}")
# 重置机器ID # Reset machine ID
print(f"{Fore.CYAN}{EMOJI['UPDATE']} {self.translator.get('register.reset_machine_id')}...{Style.RESET_ALL}") print(f"{Fore.CYAN}{EMOJI['UPDATE']} {self.translator.get('register.reset_machine_id')}...{Style.RESET_ALL}")
resetter = MachineIDResetter(self.translator) # 创建实例时传入translator resetter = MachineIDResetter(self.translator) # Pass translator when creating instance
if not resetter.reset_machine_ids(): # 直接调用reset_machine_ids方法 if not resetter.reset_machine_ids(): # Call reset_machine_ids method directly
raise Exception("Failed to reset machine ID") raise Exception("Failed to reset machine ID")
# Save account information to file # Save account information to file

View File

@@ -2,8 +2,6 @@ import os
from colorama import Fore, Style, init from colorama import Fore, Style, init
import time import time
import random import random
from browser import BrowserManager
from control import BrowserControl
from cursor_auth import CursorAuth from cursor_auth import CursorAuth
from reset_machine_manual import MachineIDResetter from reset_machine_manual import MachineIDResetter
@@ -35,7 +33,6 @@ class CursorRegistration:
self.translator = translator self.translator = translator
# Set to display mode # Set to display mode
os.environ['BROWSER_HEADLESS'] = 'False' os.environ['BROWSER_HEADLESS'] = 'False'
self.browser_manager = BrowserManager()
self.browser = None self.browser = None
self.controller = None self.controller = None
self.sign_up_url = "https://authenticator.cursor.sh/sign-up" self.sign_up_url = "https://authenticator.cursor.sh/sign-up"

View File

@@ -4,6 +4,7 @@ import platform
import shutil import shutil
from colorama import Fore, Style, init from colorama import Fore, Style, init
import subprocess import subprocess
from config import get_config
# Initialize colorama # Initialize colorama
init() init()
@@ -24,11 +25,24 @@ class AutoUpdateDisabler:
def __init__(self, translator=None): def __init__(self, translator=None):
self.translator = translator self.translator = translator
self.system = platform.system() self.system = platform.system()
self.updater_paths = {
"Windows": os.path.join(os.getenv("LOCALAPPDATA", ""), "cursor-updater"), # Get path from configuration file
"Darwin": os.path.expanduser("~/Library/Application Support/cursor-updater"), config = get_config(translator)
"Linux": os.path.expanduser("~/.config/cursor-updater") if config:
} if self.system == "Windows":
self.updater_path = config.get('WindowsPaths', 'updater_path', fallback=os.path.join(os.getenv("LOCALAPPDATA", ""), "cursor-updater"))
elif self.system == "Darwin":
self.updater_path = config.get('MacPaths', 'updater_path', fallback=os.path.expanduser("~/Library/Application Support/cursor-updater"))
elif self.system == "Linux":
self.updater_path = config.get('LinuxPaths', 'updater_path', fallback=os.path.expanduser("~/.config/cursor-updater"))
else:
# If configuration loading fails, use default paths
self.updater_paths = {
"Windows": os.path.join(os.getenv("LOCALAPPDATA", ""), "cursor-updater"),
"Darwin": os.path.expanduser("~/Library/Application Support/cursor-updater"),
"Linux": os.path.expanduser("~/.config/cursor-updater")
}
self.updater_path = self.updater_paths.get(self.system)
def _kill_cursor_processes(self): def _kill_cursor_processes(self):
"""End all Cursor processes""" """End all Cursor processes"""
@@ -50,7 +64,7 @@ class AutoUpdateDisabler:
def _remove_updater_directory(self): def _remove_updater_directory(self):
"""Delete updater directory""" """Delete updater directory"""
try: try:
updater_path = self.updater_paths.get(self.system) updater_path = self.updater_path
if not updater_path: if not updater_path:
raise OSError(self.translator.get('update.unsupported_os', system=self.system) if self.translator else f"不支持的操作系统: {self.system}") raise OSError(self.translator.get('update.unsupported_os', system=self.system) if self.translator else f"不支持的操作系统: {self.system}")
@@ -72,7 +86,7 @@ class AutoUpdateDisabler:
def _create_blocking_file(self): def _create_blocking_file(self):
"""Create blocking file""" """Create blocking file"""
try: try:
updater_path = self.updater_paths.get(self.system) updater_path = self.updater_path
if not updater_path: if not updater_path:
raise OSError(self.translator.get('update.unsupported_os', system=self.system) if self.translator else f"不支持的操作系统: {self.system}") raise OSError(self.translator.get('update.unsupported_os', system=self.system) if self.translator else f"不支持的操作系统: {self.system}")

View File

@@ -17,7 +17,8 @@
"languages": { "languages": {
"en": "English", "en": "English",
"zh_cn": "简体中文", "zh_cn": "简体中文",
"zh_tw": "繁體中文" "zh_tw": "繁體中文",
"vi": "Vietnamese"
}, },
"quit_cursor": { "quit_cursor": {
"start": "Start Quitting Cursor", "start": "Start Quitting Cursor",
@@ -160,7 +161,9 @@
"config_option_added": "Config Option Added: {option}", "config_option_added": "Config Option Added: {option}",
"config_updated": "Config Updated", "config_updated": "Config Updated",
"password_submitted": "Password Submitted", "password_submitted": "Password Submitted",
"total_usage": "Total Usage: {usage}" "total_usage": "Total Usage: {usage}",
"setting_on_password": "Setting Password",
"getting_code": "Getting Verification Code, Will Try in 60s"
}, },
"auth": { "auth": {
"title": "Cursor Auth Manager", "title": "Cursor Auth Manager",
@@ -270,6 +273,9 @@
"updating": "Updating to the latest version. The program will restart automatically.", "updating": "Updating to the latest version. The program will restart automatically.",
"up_to_date": "You are using the latest version.", "up_to_date": "You are using the latest version.",
"check_failed": "Failed to check for updates: {error}", "check_failed": "Failed to check for updates: {error}",
"continue_anyway": "Continuing with current version..." "continue_anyway": "Continuing with current version...",
"update_confirm": "Do you want to update to the latest version? (Y/n)",
"update_skipped": "Skipping update.",
"invalid_choice": "Invalid choice. Please enter 'Y' or 'n'."
} }
} }

281
locales/vi.json Normal file
View File

@@ -0,0 +1,281 @@
{
"menu": {
"title": "Các Tùy Chọn Khả Dụng",
"exit": "Thoát Chương Trình",
"reset": "Đặt Lại ID Máy",
"register": "Đăng Ký Tài Khoản Cursor Mới",
"register_manual": "Đăng Ký Cursor Với Email Tùy Chỉnh",
"quit": "Đóng Ứng Dụng Cursor",
"select_language": "Thay Đổi Ngôn Ngữ",
"input_choice": "Vui lòng nhập lựa chọn của bạn ({choices})",
"invalid_choice": "Lựa chọn không hợp lệ. Vui lòng nhập một số từ {choices}",
"program_terminated": "Chương trình đã bị người dùng chấm dứt",
"error_occurred": "Đã xảy ra lỗi: {error}. Vui lòng thử lại",
"press_enter": "Nhấn Enter để Thoát",
"disable_auto_update": "Tắt Tự Động Cập Nhật Cursor"
},
"languages": {
"en": "English",
"zh_cn": "简体中文",
"zh_tw": "繁體中文",
"vi": "Tiếng Việt"
},
"quit_cursor": {
"start": "Bắt Đầu Thoát Cursor",
"no_process": "Không Có Tiến Trình Cursor Đang Chạy",
"terminating": "Đang Chấm Dứt Tiến Trình {pid}",
"waiting": "Đang Chờ Tiến Trình Thoát",
"success": "Tất Cả Tiến Trình Cursor Đã Đóng",
"timeout": "Tiến Trình Hết Thời Gian: {pids}",
"error": "Đã Xảy Ra Lỗi: {error}"
},
"reset": {
"title": "Công Cụ Đặt Lại ID Máy Cursor",
"checking": "Đang Kiểm Tra Tệp Cấu Hình",
"not_found": "Không Tìm Thấy Tệp Cấu Hình",
"no_permission": "Không Thể Đọc Hoặc Ghi Tệp Cấu Hình, Vui Lòng Kiểm Tra Quyền Tệp",
"reading": "Đang Đọc Cấu Hình Hiện Tại",
"creating_backup": "Đang Tạo Bản Sao Lưu Cấu Hình",
"backup_exists": "Tệp Sao Lưu Đã Tồn Tại, Bỏ Qua Bước Sao Lưu",
"generating": "Đang Tạo ID Máy Mới",
"saving_json": "Đang Lưu Cấu Hình Mới Vào JSON",
"success": "Đặt Lại ID Máy Thành Công",
"new_id": "ID Máy Mới",
"permission_error": "Lỗi Quyền: {error}",
"run_as_admin": "Vui Lòng Thử Chạy Chương Trình Này Với Quyền Quản Trị",
"process_error": "Lỗi Quá Trình Đặt Lại: {error}",
"updating_sqlite": "Đang Cập Nhật Cơ Sở Dữ Liệu SQLite",
"updating_pair": "Đang Cập Nhật Cặp Khóa-Giá Trị",
"sqlite_success": "Cập Nhật Cơ Sở Dữ Liệu SQLite Thành Công",
"sqlite_error": "Cập Nhật Cơ Sở Dữ Liệu SQLite Thất Bại: {error}",
"press_enter": "Nhấn Enter để Thoát",
"unsupported_os": "Hệ Điều Hành Không Được Hỗ Trợ: {os}",
"linux_path_not_found": "Không Tìm Thấy Đường Dẫn Linux",
"updating_system_ids": "Đang Cập Nhật ID Hệ Thống",
"system_ids_updated": "Cập Nhật ID Hệ Thống Thành Công",
"system_ids_update_failed": "Cập Nhật ID Hệ Thống Thất Bại: {error}",
"windows_guid_updated": "Cập Nhật GUID Windows Thành Công",
"windows_permission_denied": "Windows Từ Chối Quyền",
"windows_guid_update_failed": "Cập Nhật GUID Windows Thất Bại",
"macos_uuid_updated": "Cập Nhật UUID macOS Thành Công",
"plutil_command_failed": "Lệnh plutil Thất Bại",
"start_patching": "Bắt Đầu Vá getMachineId",
"macos_uuid_update_failed": "Cập Nhật UUID macOS Thất Bại",
"current_version": "Phiên Bản Cursor Hiện Tại: {version}",
"patch_completed": "Vá getMachineId Hoàn Tất",
"patch_failed": "Vá getMachineId Thất Bại: {error}",
"version_check_passed": "Kiểm Tra Phiên Bản Cursor Đã Qua",
"file_modified": "Tệp Đã Được Sửa Đổi",
"version_less_than_0_45": "Phiên Bản Cursor < 0.45.0, Bỏ Qua Vá getMachineId",
"detecting_version": "Đang Phát Hiện Phiên Bản Cursor",
"patching_getmachineid": "Đang Vá getMachineId",
"version_greater_than_0_45": "Phiên Bản Cursor >= 0.45.0, Đang Vá getMachineId",
"permission_denied": "Từ Chối Quyền: {error}",
"backup_created": "Đã Tạo Bản Sao Lưu",
"update_success": "Cập Nhật Thành Công",
"update_failed": "Cập Nhật Thất Bại: {error}",
"windows_machine_guid_updated": "Cập Nhật GUID Máy Windows Thành Công",
"reading_package_json": "Đang Đọc package.json {path}",
"invalid_json_object": "Đối Tượng JSON Không Hợp Lệ",
"no_version_field": "Không Tìm Thấy Trường Phiên Bản Trong package.json",
"version_field_empty": "Trường Phiên Bản Trống",
"invalid_version_format": "Định Dạng Phiên Bản Không Hợp Lệ: {version}",
"found_version": "Đã Tìm Thấy Phiên Bản: {version}",
"version_parse_error": "Lỗi Phân Tích Phiên Bản: {error}",
"package_not_found": "Không Tìm Thấy Package.json: {path}",
"check_version_failed": "Kiểm Tra Phiên Bản Thất Bại: {error}",
"stack_trace": "Dấu Vết Ngăn Xếp",
"version_too_low": "Phiên Bản Cursor Quá Thấp: {version} < 0.45.0"
},
"register": {
"title": "Công Cụ Đăng Ký Cursor",
"start": "Bắt đầu quá trình đăng ký...",
"handling_turnstile": "Đang xử lý xác minh bảo mật...",
"retry_verification": "Đang thử lại xác minh...",
"detect_turnstile": "Đang kiểm tra xác minh bảo mật...",
"verification_success": "Xác minh bảo mật thành công",
"starting_browser": "Đang mở trình duyệt...",
"form_success": "Biểu mẫu đã được gửi thành công",
"browser_started": "Trình duyệt đã được mở thành công",
"waiting_for_second_verification": "Đang chờ xác minh email...",
"waiting_for_verification_code": "Đang chờ mã xác minh...",
"password_success": "Đặt mật khẩu thành công",
"password_error": "Không thể đặt mật khẩu: {error}. Vui lòng thử lại",
"waiting_for_page_load": "Đang tải trang...",
"first_verification_passed": "Xác minh ban đầu thành công",
"mailbox": "Đã truy cập hộp thư đến thành công",
"register_start": "Bắt Đầu Đăng Ký",
"form_submitted": "Biểu Mẫu Đã Gửi, Bắt Đầu Xác Minh...",
"filling_form": "Điền Biểu Mẫu",
"visiting_url": "Đang Truy Cập URL",
"basic_info": "Thông Tin Cơ Bản Đã Gửi",
"handle_turnstile": "Xử Lý Turnstile",
"no_turnstile": "Không Phát Hiện Turnstile",
"turnstile_passed": "Đã Vượt Qua Turnstile",
"verification_start": "Bắt Đầu Lấy Mã Xác Minh",
"verification_timeout": "Lấy Mã Xác Minh Hết Thời Gian",
"verification_not_found": "Không Tìm Thấy Mã Xác Minh",
"try_get_code": "Thử | {attempt} Lấy Mã Xác Minh | Thời Gian Còn Lại: {time}s",
"get_account": "Đang Lấy Thông Tin Tài Khoản",
"get_token": "Lấy Token Phiên Cursor",
"token_success": "Lấy Token Thành Công",
"token_attempt": "Thử | {attempt} lần để lấy Token | Sẽ thử lại sau {time}s",
"token_max_attempts": "Đạt Số Lần Thử Tối Đa ({max}) | Không Thể Lấy Token",
"token_failed": "Lấy Token Thất Bại: {error}",
"account_error": "Lấy Thông Tin Tài Khoản Thất Bại: {error}",
"press_enter": "Nhấn Enter để Thoát",
"browser_start": "Đang Khởi Động Trình Duyệt",
"open_mailbox": "Đang Mở Trang Hộp Thư",
"email_error": "Không Thể Lấy Địa Chỉ Email",
"setup_error": "Lỗi Thiết Lập Email: {error}",
"start_getting_verification_code": "Bắt Đầu Lấy Mã Xác Minh, Sẽ Thử Trong 60s",
"get_verification_code_timeout": "Lấy Mã Xác Minh Hết Thời Gian",
"get_verification_code_success": "Lấy Mã Xác Minh Thành Công",
"try_get_verification_code": "Thử | {attempt} Lấy Mã Xác Minh | Thời Gian Còn Lại: {remaining_time}s",
"verification_code_filled": "Đã Điền Mã Xác Minh",
"login_success_and_jump_to_settings_page": "Đăng Nhập Thành Công và Chuyển Đến Trang Cài Đặt",
"detect_login_page": "Phát Hiện Trang Đăng Nhập, Bắt Đầu Đăng Nhập...",
"cursor_registration_completed": "Đăng Ký Cursor Hoàn Tất!",
"set_password": "Đặt Mật Khẩu",
"basic_info_submitted": "Thông Tin Cơ Bản Đã Gửi",
"cursor_auth_info_updated": "Thông Tin Xác Thực Cursor Đã Cập Nhật",
"cursor_auth_info_update_failed": "Cập Nhật Thông Tin Xác Thực Cursor Thất Bại",
"reset_machine_id": "Đặt Lại ID Máy",
"account_info_saved": "Thông Tin Tài Khoản Đã Lưu",
"save_account_info_failed": "Lưu Thông Tin Tài Khoản Thất Bại",
"get_email_address": "Lấy Địa Chỉ Email",
"update_cursor_auth_info": "Cập Nhật Thông Tin Xác Thực Cursor",
"register_process_error": "Lỗi Quá Trình Đăng Ký: {error}",
"setting_password": "Đang Đặt Mật Khẩu",
"manual_code_input": "Nhập Mã Thủ Công",
"manual_email_input": "Nhập Email Thủ Công",
"password": "Mật Khẩu",
"first_name": "Tên",
"last_name": "Họ",
"exit_signal": "Tín Hiệu Thoát",
"email_address": "Địa Chỉ Email",
"config_created": "Đã Tạo Cấu Hình",
"verification_failed": "Xác Minh Thất Bại",
"verification_error": "Lỗi Xác Minh: {error}",
"config_option_added": "Đã Thêm Tùy Chọn Cấu Hình: {option}",
"config_updated": "Đã Cập Nhật Cấu Hình",
"password_submitted": "Đã Gửi Mật Khẩu",
"total_usage": "Tổng Sử Dụng: {usage}",
"setting_on_password": "Đang Đặt Mật Khẩu",
"getting_code": "Đang Lấy Mã Xác Minh, Sẽ Thử Trong 60s"
},
"auth": {
"title": "Trình Quản Lý Xác Thực Cursor",
"checking_auth": "Đang Kiểm Tra Tệp Xác Thực",
"auth_not_found": "Không Tìm Thấy Tệp Xác Thực",
"auth_file_error": "Lỗi Tệp Xác Thực: {error}",
"reading_auth": "Đang Đọc Tệp Xác Thực",
"updating_auth": "Đang Cập Nhật Thông Tin Xác Thực",
"auth_updated": "Cập Nhật Thông Tin Xác Thực Thành Công",
"auth_update_failed": "Cập Nhật Thông Tin Xác Thực Thất Bại: {error}",
"auth_file_created": "Đã Tạo Tệp Xác Thực",
"auth_file_create_failed": "Tạo Tệp Xác Thực Thất Bại: {error}",
"press_enter": "Nhấn Enter để Thoát",
"reset_machine_id": "Đặt Lại ID Máy",
"database_connection_closed": "Kết Nối Cơ Sở Dữ Liệu Đã Đóng",
"database_updated_successfully": "Cập Nhật Cơ Sở Dữ Liệu Thành Công",
"connected_to_database": "Đã Kết Nối Đến Cơ Sở Dữ Liệu",
"updating_pair": "Đang Cập Nhật Cặp Khóa-Giá Trị",
"db_not_found": "Không tìm thấy tệp cơ sở dữ liệu tại: {path}",
"db_permission_error": "Không thể truy cập tệp cơ sở dữ liệu. Vui lòng kiểm tra quyền",
"db_connection_error": "Không thể kết nối đến cơ sở dữ liệu: {error}"
},
"control": {
"generate_email": "Đang Tạo Email Mới",
"blocked_domain": "Tên Miền Bị Chặn",
"select_domain": "Đang Chọn Tên Miền Ngẫu Nhiên",
"copy_email": "Đang Sao Chép Địa Chỉ Email",
"enter_mailbox": "Đang Vào Hộp Thư",
"refresh_mailbox": "Đang Làm Mới Hộp Thư",
"check_verification": "Đang Kiểm Tra Mã Xác Minh",
"verification_found": "Đã Tìm Thấy Mã Xác Minh",
"verification_not_found": "Không Tìm Thấy Mã Xác Minh",
"browser_error": "Lỗi Điều Khiển Trình Duyệt: {error}",
"navigation_error": "Lỗi Điều Hướng: {error}",
"email_copy_error": "Lỗi Sao Chép Email: {error}",
"mailbox_error": "Lỗi Hộp Thư: {error}",
"token_saved_to_file": "Token Đã Lưu Vào cursor_tokens.txt",
"navigate_to": "Đang Điều Hướng Đến {url}",
"generate_email_success": "Tạo Email Thành Công",
"select_email_domain": "Chọn Tên Miền Email",
"select_email_domain_success": "Chọn Tên Miền Email Thành Công",
"get_email_name": "Lấy Tên Email",
"get_email_name_success": "Lấy Tên Email Thành Công",
"get_email_address": "Lấy Địa Chỉ Email",
"get_email_address_success": "Lấy Địa Chỉ Email Thành Công",
"enter_mailbox_success": "Vào Hộp Thư Thành Công",
"found_verification_code": "Đã Tìm Thấy Mã Xác Minh",
"get_cursor_session_token": "Lấy Token Phiên Cursor",
"get_cursor_session_token_success": "Lấy Token Phiên Cursor Thành Công",
"get_cursor_session_token_failed": "Lấy Token Phiên Cursor Thất Bại",
"save_token_failed": "Lưu Token Thất Bại",
"database_updated_successfully": "Cập Nhật Cơ Sở Dữ Liệu Thành Công",
"database_connection_closed": "Kết Nối Cơ Sở Dữ Liệu Đã Đóng",
"no_valid_verification_code": "Không Có Mã Xác Minh Hợp Lệ"
},
"email": {
"starting_browser": "Đang Khởi Động Trình Duyệt",
"visiting_site": "Đang Truy Cập mail.tm",
"create_success": "Tạo Email Thành Công",
"create_failed": "Tạo Email Thất Bại",
"create_error": "Lỗi Tạo Email: {error}",
"refreshing": "Đang Làm Mới Email",
"refresh_success": "Làm Mới Email Thành Công",
"refresh_error": "Lỗi Làm Mới Email: {error}",
"refresh_button_not_found": "Không Tìm Thấy Nút Làm Mới",
"verification_found": "Đã Tìm Thấy Xác Minh",
"verification_not_found": "Không Tìm Thấy Xác Minh",
"verification_error": "Lỗi Xác Minh: {error}",
"verification_code_found": "Đã Tìm Thấy Mã Xác Minh",
"verification_code_not_found": "Không Tìm Thấy Mã Xác Minh",
"verification_code_error": "Lỗi Mã Xác Minh: {error}",
"address": "Địa Chỉ Email",
"all_domains_blocked": "Tất Cả Tên Miền Bị Chặn, Đang Chuyển Dịch Vụ",
"no_available_domains_after_filtering": "Không Có Tên Miền Khả Dụng Sau Khi Lọc",
"switching_service": "Đang Chuyển Sang Dịch Vụ {service}",
"domains_list_error": "Không Thể Lấy Danh Sách Tên Miền: {error}",
"failed_to_get_available_domains": "Không Thể Lấy Tên Miền Khả Dụng",
"domains_excluded": "Tên Miền Bị Loại Trừ: {domains}",
"failed_to_create_account": "Không Thể Tạo Tài Khoản",
"account_creation_error": "Lỗi Tạo Tài Khoản: {error}",
"blocked_domains": "Tên Miền Bị Chặn: {domains}",
"blocked_domains_loaded": "Đã Tải Tên Miền Bị Chặn: {count}",
"blocked_domains_loaded_error": "Lỗi Tải Tên Miền Bị Chặn: {error}",
"blocked_domains_loaded_success": "Tải Tên Miền Bị Chặn Thành Công",
"blocked_domains_loaded_timeout": "Tải Tên Miền Bị Chặn Hết Thời Gian: {timeout}s",
"blocked_domains_loaded_timeout_error": "Lỗi Hết Thời Gian Tải Tên Miền Bị Chặn: {error}",
"available_domains_loaded": "Đã Tải Tên Miền Khả Dụng: {count}",
"domains_filtered": "Tên Miền Đã Lọc: {count}",
"trying_to_create_email": "Đang cố gắng tạo email: {email}"
},
"update": {
"title": "Tắt Tự Động Cập Nhật Cursor",
"disable_success": "Tắt Tự Động Cập Nhật Thành Công",
"disable_failed": "Tắt Tự Động Cập Nhật Thất Bại: {error}",
"press_enter": "Nhấn Enter để Thoát",
"start_disable": "Bắt Đầu Tắt Tự Động Cập Nhật",
"killing_processes": "Đang Kết Thúc Các Tiến Trình",
"processes_killed": "Đã Kết Thúc Các Tiến Trình",
"removing_directory": "Đang Xóa Thư Mục",
"directory_removed": "Đã Xóa Thư Mục",
"creating_block_file": "Đang Tạo Tệp Chặn",
"block_file_created": "Đã Tạo Tệp Chặn"
},
"updater": {
"checking": "Đang Kiểm Tra Cập Nhật...",
"new_version_available": "Có Phiên Bản Mới! (Hiện Tại: {current}, Mới Nhất: {latest})",
"updating": "Đang Cập Nhật Lên Phiên Bản Mới Nhất. Chương Trình Sẽ Tự Động Khởi Động Lại.",
"up_to_date": "Bạn Đang Sử Dụng Phiên Bản Mới Nhất.",
"check_failed": "Không Thể Kiểm Tra Cập Nhật: {error}",
"continue_anyway": "Tiếp Tục Với Phiên Bản Hiện Tại...",
"update_confirm": "Bạn Có Muốn Cập Nhật Lên Phiên Bản Mới Nhất Không? (Y/n)",
"update_skipped": "Bỏ Qua Cập Nhật.",
"invalid_choice": "Lựa Chọn Không Hợp Lệ. Vui Lòng Nhập 'Y' Hoặc 'n'."
}
}

View File

@@ -17,7 +17,8 @@
"languages": { "languages": {
"en": "English", "en": "English",
"zh_cn": "简体中文", "zh_cn": "简体中文",
"zh_tw": "繁體中文" "zh_tw": "繁體中文",
"vi": "Vietnamese"
}, },
"quit_cursor": { "quit_cursor": {
"start": "开始退出 Cursor", "start": "开始退出 Cursor",
@@ -159,7 +160,9 @@
"config_option_added": "配置项已添加: {option}", "config_option_added": "配置项已添加: {option}",
"config_updated": "配置已更新", "config_updated": "配置已更新",
"password_submitted": "密码已提交", "password_submitted": "密码已提交",
"total_usage": "总使用量: {usage}" "total_usage": "总使用量: {usage}",
"setting_on_password": "设置密码",
"getting_code": "获取验证码将在60秒内尝试..."
}, },
"auth": { "auth": {
"title": "Cursor 认证管理器", "title": "Cursor 认证管理器",
@@ -266,6 +269,9 @@
"updating": "正在更新到最新版本。程序将自动重启。", "updating": "正在更新到最新版本。程序将自动重启。",
"up_to_date": "您使用的是最新版本。", "up_to_date": "您使用的是最新版本。",
"check_failed": "检查更新失败: {error}", "check_failed": "检查更新失败: {error}",
"continue_anyway": "继续使用当前版本..." "continue_anyway": "继续使用当前版本...",
"update_confirm": "是否要更新到最新版本? (Y/n)",
"update_skipped": "跳过更新。",
"invalid_choice": "选择无效。请输入 'Y' 或 'n'."
} }
} }

View File

@@ -17,7 +17,8 @@
"languages": { "languages": {
"en": "English", "en": "English",
"zh_cn": "简体中文", "zh_cn": "简体中文",
"zh_tw": "繁體中文" "zh_tw": "繁體中文",
"vi": "Vietnamese"
}, },
"quit_cursor": { "quit_cursor": {
"start": "開始退出 Cursor", "start": "開始退出 Cursor",
@@ -141,7 +142,9 @@
"config_option_added": "配置項已添加: {option}", "config_option_added": "配置項已添加: {option}",
"config_updated": "配置已更新", "config_updated": "配置已更新",
"password_submitted": "密碼已提交", "password_submitted": "密碼已提交",
"total_usage": "總使用量: {usage}" "total_usage": "總使用量: {usage}",
"setting_on_password": "設置密碼",
"getting_code": "正在獲取驗證碼將在60秒內嘗試..."
}, },
"auth": { "auth": {
"title": "Cursor 認證管理器", "title": "Cursor 認證管理器",
@@ -248,6 +251,9 @@
"updating": "正在更新到最新版本。程序將自動重啟。", "updating": "正在更新到最新版本。程序將自動重啟。",
"up_to_date": "您使用的是最新版本。", "up_to_date": "您使用的是最新版本。",
"check_failed": "檢查更新失敗: {error}", "check_failed": "檢查更新失敗: {error}",
"continue_anyway": "繼續使用當前版本..." "continue_anyway": "繼續使用當前版本...",
"update_confirm": "是否要更新到最新版本? (Y/n)",
"update_skipped": "跳過更新。",
"invalid_choice": "選擇無效。請輸入 'Y' 或 'n'."
} }
} }

84
main.py
View File

@@ -9,17 +9,18 @@ import locale
import platform import platform
import requests import requests
import subprocess import subprocess
from config import get_config
# 只在 Windows 系统上导入 windll # Only import windll on Windows systems
if platform.system() == 'Windows': if platform.system() == 'Windows':
import ctypes import ctypes
# 只在 Windows 上导入 windll # 只在 Windows 上导入 windll
from ctypes import windll from ctypes import windll
# 初始化colorama # Initialize colorama
init() init()
# 定义emoji和颜色常量 # Define emoji and color constants
EMOJI = { EMOJI = {
"FILE": "📄", "FILE": "📄",
"BACKUP": "💾", "BACKUP": "💾",
@@ -30,13 +31,47 @@ EMOJI = {
"MENU": "📋", "MENU": "📋",
"ARROW": "", "ARROW": "",
"LANG": "🌐", "LANG": "🌐",
"UPDATE": "🔄" "UPDATE": "🔄",
"ADMIN": "🔐"
} }
# Function to check if running as frozen executable
def is_frozen():
"""Check if the script is running as a frozen executable."""
return getattr(sys, 'frozen', False)
# Function to check admin privileges (Windows only)
def is_admin():
"""Check if the script is running with admin privileges (Windows only)."""
if platform.system() == 'Windows':
try:
return ctypes.windll.shell32.IsUserAnAdmin() != 0
except Exception:
return False
# Always return True for non-Windows to avoid changing behavior
return True
# Function to restart with admin privileges
def run_as_admin():
"""Restart the current script with admin privileges (Windows only)."""
if platform.system() != 'Windows':
return False
try:
args = [sys.executable] + sys.argv
# Request elevation via ShellExecute
print(f"{Fore.YELLOW}{EMOJI['ADMIN']} Requesting administrator privileges...{Style.RESET_ALL}")
ctypes.windll.shell32.ShellExecuteW(None, "runas", args[0], " ".join('"' + arg + '"' for arg in args[1:]), None, 1)
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Failed to restart with admin privileges: {e}{Style.RESET_ALL}")
return False
class Translator: class Translator:
def __init__(self): def __init__(self):
self.translations = {} self.translations = {}
self.current_language = self.detect_system_language() # 使用正确的方法名 self.current_language = self.detect_system_language() # Use correct method name
self.fallback_language = 'en' # Fallback language if translation is missing self.fallback_language = 'en' # Fallback language if translation is missing
self.load_translations() self.load_translations()
@@ -57,11 +92,11 @@ class Translator:
def _detect_windows_language(self): def _detect_windows_language(self):
"""Detect language on Windows systems""" """Detect language on Windows systems"""
try: try:
# 确保我们在 Windows # Ensure we are on Windows
if platform.system() != 'Windows': if platform.system() != 'Windows':
return 'en' return 'en'
# 获取键盘布局 # Get keyboard layout
user32 = ctypes.windll.user32 user32 = ctypes.windll.user32
hwnd = user32.GetForegroundWindow() hwnd = user32.GetForegroundWindow()
threadid = user32.GetWindowThreadProcessId(hwnd, 0) threadid = user32.GetWindowThreadProcessId(hwnd, 0)
@@ -72,6 +107,7 @@ class Translator:
0x0409: 'en', # English 0x0409: 'en', # English
0x0404: 'zh_tw', # Traditional Chinese 0x0404: 'zh_tw', # Traditional Chinese
0x0804: 'zh_cn', # Simplified Chinese 0x0804: 'zh_cn', # Simplified Chinese
0x0422: 'vi', # Vietnamese
} }
return language_map.get(layout_id, 'en') return language_map.get(layout_id, 'en')
@@ -95,14 +131,20 @@ class Translator:
return 'zh_cn' return 'zh_cn'
elif system_locale.startswith('en'): elif system_locale.startswith('en'):
return 'en' return 'en'
elif system_locale.startswith('vi'):
return 'vi'
# Try to get language from LANG environment variable as fallback # Try to get language from LANG environment variable as fallback
env_lang = os.getenv('LANG', '').lower() env_lang = os.getenv('LANG', '').lower()
if 'tw' in env_lang or 'hk' in env_lang: if 'tw' in env_lang or 'hk' in env_lang:
return 'zh_tw' return 'zh_tw'
elif 'cn' in env_lang: elif 'cn' in env_lang:
return 'zh_cn' return 'zh_cn'
elif 'vi' in env_lang:
return 'vi'
return 'en' return 'en'
except: except:
return 'en' return 'en'
@@ -167,11 +209,11 @@ class Translator:
"""Get list of available languages""" """Get list of available languages"""
return list(self.translations.keys()) return list(self.translations.keys())
# 创建翻译器实例 # Create translator instance
translator = Translator() translator = Translator()
def print_menu(): def print_menu():
"""打印菜单选项""" """Print menu options"""
print(f"\n{Fore.CYAN}{EMOJI['MENU']} {translator.get('menu.title')}:{Style.RESET_ALL}") print(f"\n{Fore.CYAN}{EMOJI['MENU']} {translator.get('menu.title')}:{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{'' * 40}{Style.RESET_ALL}") print(f"{Fore.YELLOW}{'' * 40}{Style.RESET_ALL}")
print(f"{Fore.GREEN}0{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.exit')}") print(f"{Fore.GREEN}0{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.exit')}")
@@ -238,6 +280,17 @@ def check_latest_version():
if latest_version != version: if latest_version != version:
print(f"\n{Fore.YELLOW}{EMOJI['INFO']} {translator.get('updater.new_version_available', current=version, latest=latest_version)}{Style.RESET_ALL}") print(f"\n{Fore.YELLOW}{EMOJI['INFO']} {translator.get('updater.new_version_available', current=version, latest=latest_version)}{Style.RESET_ALL}")
# Ask user if they want to update
while True:
choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('updater.update_confirm', choices='Y/n')}: {Style.RESET_ALL}").lower()
if choice in ['', 'y', 'yes']:
break
elif choice in ['n', 'no']:
print(f"\n{Fore.YELLOW}{EMOJI['INFO']} {translator.get('updater.update_skipped')}{Style.RESET_ALL}")
return
else:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
try: try:
# Execute update command based on platform # Execute update command based on platform
if platform.system() == 'Windows': if platform.system() == 'Windows':
@@ -284,11 +337,18 @@ def check_latest_version():
return return
def main(): def main():
# Check for admin privileges if running as executable on Windows only
if platform.system() == 'Windows' and is_frozen() and not is_admin():
print(f"{Fore.YELLOW}{EMOJI['ADMIN']} Running as executable, administrator privileges required.{Style.RESET_ALL}")
if run_as_admin():
sys.exit(0) # Exit after requesting admin privileges
else:
print(f"{Fore.YELLOW}{EMOJI['INFO']} Continuing without administrator privileges.{Style.RESET_ALL}")
print_logo() print_logo()
# 初始化配置 # Initialize configuration
from new_signup import setup_config config = get_config(translator)
config = setup_config(translator)
if not config: if not config:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.config_init_failed')}{Style.RESET_ALL}") print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.config_init_failed')}{Style.RESET_ALL}")
return return

View File

@@ -7,13 +7,14 @@ from colorama import Fore, Style
import configparser import configparser
from pathlib import Path from pathlib import Path
import sys import sys
from config import get_config
# 在文件开头添加全局变量 # Add global variable at the beginning of the file
_translator = None _translator = None
def cleanup_chrome_processes(translator=None): def cleanup_chrome_processes(translator=None):
"""清理所有Chrome相关进程""" """Clean all Chrome related processes"""
print("\n正在清理Chrome进程...") print("\nCleaning Chrome processes...")
try: try:
if os.name == 'nt': if os.name == 'nt':
os.system('taskkill /F /IM chrome.exe /T 2>nul') os.system('taskkill /F /IM chrome.exe /T 2>nul')
@@ -28,7 +29,7 @@ def cleanup_chrome_processes(translator=None):
print(f"清理进程时出错: {e}") print(f"清理进程时出错: {e}")
def signal_handler(signum, frame): def signal_handler(signum, frame):
"""处理Ctrl+C信号""" """Handle Ctrl+C signal"""
global _translator global _translator
if _translator: if _translator:
print(f"{Fore.CYAN}{_translator.get('register.exit_signal')}{Style.RESET_ALL}") print(f"{Fore.CYAN}{_translator.get('register.exit_signal')}{Style.RESET_ALL}")
@@ -38,45 +39,45 @@ def signal_handler(signum, frame):
os._exit(0) os._exit(0)
def simulate_human_input(page, url, config, translator=None): def simulate_human_input(page, url, config, translator=None):
"""访问网址""" """Visit URL"""
if translator: if translator:
print(f"{Fore.CYAN}🚀 {translator.get('register.visiting_url')}: {url}{Style.RESET_ALL}") print(f"{Fore.CYAN}🚀 {translator.get('register.visiting_url')}: {url}{Style.RESET_ALL}")
# 先访问空白页面 # First visit blank page
page.get('about:blank') page.get('about:blank')
time.sleep(get_random_wait_time(config, 'page_load_wait')) time.sleep(get_random_wait_time(config, 'page_load_wait'))
# 访问目标页面 # Visit target page
page.get(url) page.get(url)
time.sleep(get_random_wait_time(config, 'page_load_wait')) time.sleep(get_random_wait_time(config, 'page_load_wait'))
def fill_signup_form(page, first_name, last_name, email, config, translator=None): def fill_signup_form(page, first_name, last_name, email, config, translator=None):
"""填写注册表单""" """Fill signup form"""
try: try:
if translator: if translator:
print(f"{Fore.CYAN}📧 {translator.get('register.filling_form')}{Style.RESET_ALL}") print(f"{Fore.CYAN}📧 {translator.get('register.filling_form')}{Style.RESET_ALL}")
else: else:
print("\n正在填写注册表单...") print("\n正在填写注册表单...")
# 填写名字 # Fill first name
first_name_input = page.ele("@name=first_name") first_name_input = page.ele("@name=first_name")
if first_name_input: if first_name_input:
first_name_input.input(first_name) first_name_input.input(first_name)
time.sleep(get_random_wait_time(config, 'input_wait')) time.sleep(get_random_wait_time(config, 'input_wait'))
# 填写姓氏 # Fill last name
last_name_input = page.ele("@name=last_name") last_name_input = page.ele("@name=last_name")
if last_name_input: if last_name_input:
last_name_input.input(last_name) last_name_input.input(last_name)
time.sleep(get_random_wait_time(config, 'input_wait')) time.sleep(get_random_wait_time(config, 'input_wait'))
# 填写邮箱 # Fill email
email_input = page.ele("@name=email") email_input = page.ele("@name=email")
if email_input: if email_input:
email_input.input(email) email_input.input(email)
time.sleep(get_random_wait_time(config, 'input_wait')) time.sleep(get_random_wait_time(config, 'input_wait'))
# 点击提交按钮 # Click submit button
submit_button = page.ele("@type=submit") submit_button = page.ele("@type=submit")
if submit_button: if submit_button:
submit_button.click() submit_button.click()
@@ -85,14 +86,14 @@ def fill_signup_form(page, first_name, last_name, email, config, translator=None
if translator: if translator:
print(f"{Fore.GREEN}{translator.get('register.form_success')}{Style.RESET_ALL}") print(f"{Fore.GREEN}{translator.get('register.form_success')}{Style.RESET_ALL}")
else: else:
print("表单填写完成") print("Form filled successfully")
return True return True
except Exception as e: except Exception as e:
if translator: if translator:
print(f"{Fore.RED}{translator.get('register.form_error', error=str(e))}{Style.RESET_ALL}") print(f"{Fore.RED}{translator.get('register.form_error', error=str(e))}{Style.RESET_ALL}")
else: else:
print(f"填写表单时出错: {e}") print(f"Error filling form: {e}")
return False return False
def get_default_chrome_path(): def get_default_chrome_path():
@@ -142,7 +143,7 @@ def get_random_wait_time(config, timing_type='page_load_wait'):
""" """
try: try:
if not config.has_section('Timing'): if not config.has_section('Timing'):
return random.uniform(0.1, 0.8) # 默认值 return random.uniform(0.1, 0.8) # Default value
if timing_type == 'random': if timing_type == 'random':
min_time = float(config.get('Timing', 'min_random_time', fallback='0.1')) min_time = float(config.get('Timing', 'min_random_time', fallback='0.1'))
@@ -151,130 +152,21 @@ def get_random_wait_time(config, timing_type='page_load_wait'):
time_value = config.get('Timing', timing_type, fallback='0.1-0.8') time_value = config.get('Timing', timing_type, fallback='0.1-0.8')
# 检查是否为固定时间值 # Check if it's a fixed time value
if '-' not in time_value and ',' not in time_value: if '-' not in time_value and ',' not in time_value:
return float(time_value) # 返回固定时间 return float(time_value) # Return fixed time
# 处理范围时间 # Process range time
min_time, max_time = map(float, time_value.split('-' if '-' in time_value else ',')) min_time, max_time = map(float, time_value.split('-' if '-' in time_value else ','))
return random.uniform(min_time, max_time) return random.uniform(min_time, max_time)
except: except:
return random.uniform(0.1, 0.8) # 出错时返回默认值 return random.uniform(0.1, 0.8) # Return default value when error
def setup_config(translator=None):
"""Setup configuration file and return config object"""
try:
# Set configuration file path
config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip")
config_file = os.path.join(config_dir, "config.ini")
# Create config directory (if it doesn't exist)
os.makedirs(config_dir, exist_ok=True)
# Read or create configuration file
config = configparser.ConfigParser()
# 默认配置
default_config = {
'Chrome': {
'chromepath': get_default_chrome_path()
},
'Turnstile': {
'handle_turnstile_time': '2',
'handle_turnstile_random_time': '1-3'
},
'Timing': {
'min_random_time': '0.1',
'max_random_time': '0.8',
'page_load_wait': '0.1-0.8',
'input_wait': '0.3-0.8',
'submit_wait': '0.5-1.5',
'verification_code_input': '0.1-0.3', # 验证码输入间隔
'verification_success_wait': '2-3', # 验证成功后等待
'verification_retry_wait': '2-3', # 验证重试等待
'email_check_initial_wait': '4-6', # 首次等待邮件时间
'email_refresh_wait': '2-4', # 邮箱刷新等待时间
'settings_page_load_wait': '1-2', # 设置页面加载等待
'failed_retry_time': '0.5-1', # 验证失败重试等待时间
'retry_interval': '8-12', # 重试间隔时间
'max_timeout': '160' # 最大超时时间
}
}
# Add OS-specific path configurations
if sys.platform == "win32":
appdata = os.getenv("APPDATA")
default_config['WindowsPaths'] = {
'storage_path': os.path.join(appdata, "Cursor", "User", "globalStorage", "storage.json"),
'sqlite_path': os.path.join(appdata, "Cursor", "User", "globalStorage", "state.vscdb"),
'machine_id_path': os.path.join(os.getenv("APPDATA"), "Cursor", "machineId"),
'cursor_path': os.path.join(os.getenv("LOCALAPPDATA", ""), "Programs", "Cursor", "resources", "app")
}
elif sys.platform == "darwin":
default_config['MacPaths'] = {
'storage_path': os.path.abspath(os.path.expanduser("~/Library/Application Support/Cursor/User/globalStorage/storage.json")),
'sqlite_path': os.path.abspath(os.path.expanduser("~/Library/Application Support/Cursor/User/globalStorage/state.vscdb")),
'machine_id_path': os.path.expanduser("~/Library/Application Support/Cursor/machineId"),
'cursor_path': "/Applications/Cursor.app/Contents/Resources/app"
}
elif sys.platform == "linux":
sudo_user = os.environ.get('SUDO_USER')
actual_home = f"/home/{sudo_user}" if sudo_user else os.path.expanduser("~")
default_config['LinuxPaths'] = {
'storage_path': os.path.abspath(os.path.join(actual_home, ".config/Cursor/User/globalStorage/storage.json")),
'sqlite_path': os.path.abspath(os.path.join(actual_home, ".config/Cursor/User/globalStorage/state.vscdb")),
'machine_id_path': os.path.expanduser("~/.config/Cursor/machineId"),
'cursor_path': "/opt/Cursor/resources/app" # 默認路徑
}
if os.path.exists(config_file):
config.read(config_file)
config_modified = False
# 检查并添加缺失的配置项
for section, options in default_config.items():
if not config.has_section(section):
config.add_section(section)
config_modified = True
for option, value in options.items():
if not config.has_option(section, option):
config.set(section, option, value)
config_modified = True
if translator:
print(f"{Fore.YELLOW} {translator.get('register.config_option_added', option=f'{section}.{option}') if translator else f'添加配置项: {section}.{option}'}{Style.RESET_ALL}")
# 如果有新增配置项,保存文件
if config_modified:
with open(config_file, 'w', encoding='utf-8') as f:
config.write(f)
if translator:
print(f"{Fore.GREEN}{translator.get('register.config_updated') if translator else '配置文件已更新'}{Style.RESET_ALL}")
else:
# 创建新配置文件
config = configparser.ConfigParser()
for section, options in default_config.items():
config.add_section(section)
for option, value in options.items():
config.set(section, option, value)
with open(config_file, 'w', encoding='utf-8') as f:
config.write(f)
if translator:
print(f"{Fore.GREEN}{translator.get('register.config_created') if translator else '已创建配置文件'}: {config_file}{Style.RESET_ALL}")
return config
except Exception as e:
if translator:
print(f"{Fore.RED}{translator.get('register.config_setup_error', error=str(e)) if translator else f'配置设置出错: {str(e)}'}{Style.RESET_ALL}")
raise
def setup_driver(translator=None): def setup_driver(translator=None):
"""Setup browser driver""" """Setup browser driver"""
try: try:
# 获取配置 # Get config
config = setup_config(translator) config = get_config(translator)
# Get Chrome path # Get Chrome path
chrome_path = config.get('Chrome', 'chromepath', fallback=get_default_chrome_path()) chrome_path = config.get('Chrome', 'chromepath', fallback=get_default_chrome_path())
@@ -293,17 +185,17 @@ def setup_driver(translator=None):
# Use incognito mode # Use incognito mode
co.set_argument("--incognito") co.set_argument("--incognito")
# 设置随机端口 # Set random port
co.set_argument("--no-sandbox") co.set_argument("--no-sandbox")
# 设置随机端口 # Set random port
co.auto_port() co.auto_port()
# 使用有头模式(一定要设置为False模拟人类操作) # Use headless mode (must be set to False, simulate human operation)
co.headless(False) co.headless(False)
try: try:
# 加载插件 # Load extension
extension_path = os.path.join(os.getcwd(), "turnstilePatch") extension_path = os.path.join(os.getcwd(), "turnstilePatch")
if os.path.exists(extension_path): if os.path.exists(extension_path):
co.set_argument("--allow-extensions-in-incognito") co.set_argument("--allow-extensions-in-incognito")
@@ -312,12 +204,12 @@ def setup_driver(translator=None):
if translator: if translator:
print(f"{Fore.RED}{translator.get('register.extension_load_error', error=str(e))}{Style.RESET_ALL}") print(f"{Fore.RED}{translator.get('register.extension_load_error', error=str(e))}{Style.RESET_ALL}")
else: else:
print(f"加载插件失败: {e}") print(f"Error loading extension: {e}")
if translator: if translator:
print(f"{Fore.CYAN}🚀 {translator.get('register.starting_browser')}{Style.RESET_ALL}") print(f"{Fore.CYAN}🚀 {translator.get('register.starting_browser')}{Style.RESET_ALL}")
else: else:
print("正在启动浏览器...") print("Starting browser...")
page = ChromiumPage(co) page = ChromiumPage(co)
return config, page return config, page
@@ -326,26 +218,26 @@ def setup_driver(translator=None):
if translator: if translator:
print(f"{Fore.RED}{translator.get('register.browser_setup_error', error=str(e))}{Style.RESET_ALL}") print(f"{Fore.RED}{translator.get('register.browser_setup_error', error=str(e))}{Style.RESET_ALL}")
else: else:
print(f"设置浏览器时出错: {e}") print(f"Error setting up browser: {e}")
raise raise
def handle_turnstile(page, config, translator=None): def handle_turnstile(page, config, translator=None):
"""处理 Turnstile 验证""" """Handle Turnstile verification"""
try: try:
if translator: if translator:
print(f"{Fore.CYAN}🔄 {translator.get('register.handling_turnstile')}{Style.RESET_ALL}") print(f"{Fore.CYAN}🔄 {translator.get('register.handling_turnstile')}{Style.RESET_ALL}")
else: else:
print("\n正在处理 Turnstile 验证...") print("\nHandling Turnstile verification...")
# from config # from config
turnstile_time = float(config.get('Turnstile', 'handle_turnstile_time', fallback='2')) turnstile_time = float(config.get('Turnstile', 'handle_turnstile_time', fallback='2'))
random_time_str = config.get('Turnstile', 'handle_turnstile_random_time', fallback='1-3') random_time_str = config.get('Turnstile', 'handle_turnstile_random_time', fallback='1-3')
# 解析随机时间范围 # Parse random time range
try: try:
min_time, max_time = map(float, random_time_str.split('-')) min_time, max_time = map(float, random_time_str.split('-'))
except: except:
min_time, max_time = 1, 3 # 默认值 min_time, max_time = 1, 3 # Default value
max_retries = 2 max_retries = 2
retry_count = 0 retry_count = 0
@@ -355,14 +247,14 @@ def handle_turnstile(page, config, translator=None):
if translator: if translator:
print(f"{Fore.CYAN}🔄 {translator.get('register.retry_verification', attempt=retry_count)}{Style.RESET_ALL}") print(f"{Fore.CYAN}🔄 {translator.get('register.retry_verification', attempt=retry_count)}{Style.RESET_ALL}")
else: else:
print(f" {retry_count} 次尝试验证...") print(f"Attempt {retry_count} of verification...")
try: try:
# 尝试重置 turnstile # Try to reset turnstile
page.run_js("try { turnstile.reset() } catch(e) { }") page.run_js("try { turnstile.reset() } catch(e) { }")
time.sleep(turnstile_time) # from config time.sleep(turnstile_time) # from config
# 定位验证框元素 # Locate verification box element
challenge_check = ( challenge_check = (
page.ele("@id=cf-turnstile", timeout=2) page.ele("@id=cf-turnstile", timeout=2)
.child() .child()
@@ -375,7 +267,7 @@ def handle_turnstile(page, config, translator=None):
if translator: if translator:
print(f"{Fore.CYAN}🔄 {translator.get('register.detect_turnstile')}{Style.RESET_ALL}") print(f"{Fore.CYAN}🔄 {translator.get('register.detect_turnstile')}{Style.RESET_ALL}")
else: else:
print("检测到验证框...") print("Detected verification box...")
# from config # from config
time.sleep(random.uniform(min_time, max_time)) time.sleep(random.uniform(min_time, max_time))
@@ -387,21 +279,21 @@ def handle_turnstile(page, config, translator=None):
if translator: if translator:
print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}") print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}")
else: else:
print("验证通过!") print("Verification successful!")
return True return True
except Exception as e: except Exception as e:
if translator: if translator:
print(f"{Fore.RED}{translator.get('register.verification_failed')}{Style.RESET_ALL}") print(f"{Fore.RED}{translator.get('register.verification_failed')}{Style.RESET_ALL}")
else: else:
print(f"验证尝试失败: {e}") print(f"Verification attempt failed: {e}")
# 检查是否已经验证成功 # Check if verification has been successful
if check_verification_success(page, translator): if check_verification_success(page, translator):
if translator: if translator:
print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}") print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}")
else: else:
print("验证通过!") print("Verification successful!")
return True return True
time.sleep(random.uniform(min_time, max_time)) time.sleep(random.uniform(min_time, max_time))
@@ -409,27 +301,27 @@ def handle_turnstile(page, config, translator=None):
if translator: if translator:
print(f"{Fore.RED}{translator.get('register.verification_failed')}{Style.RESET_ALL}") print(f"{Fore.RED}{translator.get('register.verification_failed')}{Style.RESET_ALL}")
else: else:
print("超出最大重试次数") print("Exceeded maximum retry attempts")
return False return False
except Exception as e: except Exception as e:
if translator: if translator:
print(f"{Fore.RED}{translator.get('register.verification_error', error=str(e))}{Style.RESET_ALL}") print(f"{Fore.RED}{translator.get('register.verification_error', error=str(e))}{Style.RESET_ALL}")
else: else:
print(f"验证过程出错: {e}") print(f"Error in verification process: {e}")
return False return False
def check_verification_success(page, translator=None): def check_verification_success(page, translator=None):
"""检查验证是否成功""" """Check if verification is successful"""
try: try:
# 检查是否存在后续表单元素,这表示验证已通过 # Check if there is a subsequent form element, indicating verification has passed
if (page.ele("@name=password", timeout=0.5) or if (page.ele("@name=password", timeout=0.5) or
page.ele("@name=email", timeout=0.5) or page.ele("@name=email", timeout=0.5) or
page.ele("@data-index=0", timeout=0.5) or page.ele("@data-index=0", timeout=0.5) or
page.ele("Account Settings", timeout=0.5)): page.ele("Account Settings", timeout=0.5)):
return True return True
# 检查是否出现错误消息 # Check if there is an error message
error_messages = [ error_messages = [
'xpath://div[contains(text(), "Can\'t verify the user is human")]', 'xpath://div[contains(text(), "Can\'t verify the user is human")]',
'xpath://div[contains(text(), "Error: 600010")]', 'xpath://div[contains(text(), "Error: 600010")]',
@@ -445,67 +337,49 @@ def check_verification_success(page, translator=None):
return False return False
def generate_password(length=12): def generate_password(length=12):
"""生成随机密码""" """Generate random password"""
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*" chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
return ''.join(random.choices(chars, k=length)) return ''.join(random.choices(chars, k=length))
def fill_password(page, password: str, config, translator=None) -> bool: def fill_password(page, password: str, config, translator=None):
""" """
填写密码表单 Fill password form
""" """
try: try:
print(f"{Fore.CYAN}🔑 {translator.get('register.setting_password') if translator else '设置密码'}{Style.RESET_ALL}") print(f"{Fore.CYAN}🔑 {translator.get('register.setting_password') if translator else 'Setting password'}{Style.RESET_ALL}")
# 等待密码框出现并尝试多次 # Fill password
max_retries = 5 password_input = page.ele("@name=password")
for i in range(max_retries): print(f"{Fore.CYAN}🔑 {translator.get('register.setting_on_password')}: {password}{Style.RESET_ALL}")
# 检查是否出现错误信息 if password_input:
if page.ele("This email is not available."): password_input.input(password)
print(f"{Fore.RED}{translator.get('register.email_used') if translator else '注册失败:邮箱已被使用'}{Style.RESET_ALL}")
return False
# 查找密码输入框 # Click submit button
password_input = page.ele("@name=password") submit_button = page.ele("@type=submit")
if password_input: if submit_button:
# 清除可能存在的旧值并输入新密码 submit_button.click()
password_input.click() time.sleep(get_random_wait_time(config, 'submit_wait'))
time.sleep(get_random_wait_time(config, 'input_wait'))
password_input.input(password)
time.sleep(get_random_wait_time(config, 'input_wait'))
# 查找并点击提交按钮
submit_button = page.ele("@type=submit")
if submit_button:
submit_button.click()
print(f"{Fore.GREEN}{translator.get('register.password_submitted') if translator else '密码已提交'}{Style.RESET_ALL}")
time.sleep(get_random_wait_time(config, 'submit_wait'))
return True
else:
print(f"{Fore.YELLOW}⚠️ {translator.get('register.retry_submit') if translator else '未找到提交按钮,重试中...'}{Style.RESET_ALL}")
# 如果没找到密码框,等待后重试 print(f"{Fore.GREEN}{translator.get('register.password_submitted') if translator else 'Password submitted'}{Style.RESET_ALL}")
time.sleep(get_random_wait_time(config, 'failed_retry_time'))
if i < max_retries - 1: # 不是最后一次尝试时才打印 return True
print(f"{Fore.YELLOW}⚠️ {translator.get('register.retry_password', attempt=i+1) if translator else f'{i+1} 次尝试设置密码...'}{Style.RESET_ALL}")
print(f"{Fore.RED}{translator.get('register.password_set_failed') if translator else '密码设置失败:超过重试次数'}{Style.RESET_ALL}")
return False
except Exception as e: except Exception as e:
print(f"{Fore.RED}{translator.get('register.password_error', error=str(e)) if translator else f'设置密码时出错: {str(e)}'}{Style.RESET_ALL}") print(f"{Fore.RED}{translator.get('register.password_error', error=str(e)) if translator else f'Error setting password: {str(e)}'}{Style.RESET_ALL}")
return False return False
def handle_verification_code(browser_tab, email_tab, controller, email, password, config, translator=None): def handle_verification_code(browser_tab, email_tab, controller, config, translator=None):
"""处理验证码""" """Handle verification code"""
try: try:
if translator: if translator:
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}") print(f"\n{Fore.CYAN}🔄 {translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
# 检查是否使用手动输入验证码 # Check if using manual input verification code
if hasattr(controller, 'get_verification_code') and email_tab is None: # 手动模式 if hasattr(controller, 'get_verification_code') and email_tab is None: # Manual mode
verification_code = controller.get_verification_code() verification_code = controller.get_verification_code()
if verification_code: if verification_code:
# 在注册页面填写验证码 # Fill verification code in registration page
for i, digit in enumerate(verification_code): for i, digit in enumerate(verification_code):
browser_tab.ele(f"@data-index={i}").input(digit) browser_tab.ele(f"@data-index={i}").input(digit)
time.sleep(get_random_wait_time(config, 'verification_code_input')) time.sleep(get_random_wait_time(config, 'verification_code_input'))
@@ -513,34 +387,34 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
print(f"{translator.get('register.verification_success')}") print(f"{translator.get('register.verification_success')}")
time.sleep(get_random_wait_time(config, 'verification_success_wait')) time.sleep(get_random_wait_time(config, 'verification_success_wait'))
# 处理最后一次 Turnstile 验证 # Handle last Turnstile verification
if handle_turnstile(browser_tab, config, translator): if handle_turnstile(browser_tab, config, translator):
if translator: if translator:
print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}") print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}")
time.sleep(get_random_wait_time(config, 'verification_retry_wait')) time.sleep(get_random_wait_time(config, 'verification_retry_wait'))
# 访问设置页面 # Visit settings page
print(f"{Fore.CYAN} {translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}") print(f"{Fore.CYAN}🔑 {translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}")
browser_tab.get("https://www.cursor.com/settings") browser_tab.get("https://www.cursor.com/settings")
time.sleep(get_random_wait_time(config, 'settings_page_load_wait')) time.sleep(get_random_wait_time(config, 'settings_page_load_wait'))
return True, browser_tab return True, browser_tab
return False, None return False, None
# 自动获取验证码逻辑 # Automatic verification code logic
elif email_tab: elif email_tab:
print(f"{translator.get('register.waiting_for_verification_code')}") print(f"{Fore.CYAN}🔄 {translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
time.sleep(get_random_wait_time(config, 'email_check_initial_wait')) time.sleep(get_random_wait_time(config, 'email_check_initial_wait'))
# 使用已有的 email_tab 刷新邮箱 # Use existing email_tab to refresh email
email_tab.refresh_inbox() email_tab.refresh_inbox()
time.sleep(get_random_wait_time(config, 'email_refresh_wait')) time.sleep(get_random_wait_time(config, 'email_refresh_wait'))
# 检查邮箱是否有验证码邮件 # Check if there is a verification code email
if email_tab.check_for_cursor_email(): if email_tab.check_for_cursor_email():
verification_code = email_tab.get_verification_code() verification_code = email_tab.get_verification_code()
if verification_code: if verification_code:
# 在注册页面填写验证码 # Fill verification code in registration page
for i, digit in enumerate(verification_code): for i, digit in enumerate(verification_code):
browser_tab.ele(f"@data-index={i}").input(digit) browser_tab.ele(f"@data-index={i}").input(digit)
time.sleep(get_random_wait_time(config, 'verification_code_input')) time.sleep(get_random_wait_time(config, 'verification_code_input'))
@@ -549,13 +423,13 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}") print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}")
time.sleep(get_random_wait_time(config, 'verification_success_wait')) time.sleep(get_random_wait_time(config, 'verification_success_wait'))
# 处理最后一次 Turnstile 验证 # Handle last Turnstile verification
if handle_turnstile(browser_tab, config, translator): if handle_turnstile(browser_tab, config, translator):
if translator: if translator:
print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}") print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}")
time.sleep(get_random_wait_time(config, 'verification_retry_wait')) time.sleep(get_random_wait_time(config, 'verification_retry_wait'))
# 访问设置页面 # Visit settings page
if translator: if translator:
print(f"{Fore.CYAN}🔑 {translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}") print(f"{Fore.CYAN}🔑 {translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}")
browser_tab.get("https://www.cursor.com/settings") browser_tab.get("https://www.cursor.com/settings")
@@ -569,18 +443,18 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
print("最后一次验证失败") print("最后一次验证失败")
return False, None return False, None
# 获取验证码,设置超时 # Get verification code, set timeout
verification_code = None verification_code = None
max_attempts = 20 max_attempts = 20
retry_interval = get_random_wait_time(config, 'retry_interval') # 使用 get_random_wait_time retry_interval = get_random_wait_time(config, 'retry_interval') # Use get_random_wait_time
start_time = time.time() start_time = time.time()
timeout = float(config.get('Timing', 'max_timeout', fallback='160')) # 這個可以保持不變因為是固定值 timeout = float(config.get('Timing', 'max_timeout', fallback='160')) # This can be kept unchanged because it is a fixed value
if translator: if translator:
print(f"{Fore.CYAN}{translator.get('register.start_getting_verification_code')}{Style.RESET_ALL}") print(f"{Fore.CYAN}{translator.get('register.start_getting_verification_code')}{Style.RESET_ALL}")
for attempt in range(max_attempts): for attempt in range(max_attempts):
# 检查是否超时 # Check if timeout
if time.time() - start_time > timeout: if time.time() - start_time > timeout:
if translator: if translator:
print(f"{Fore.RED}{translator.get('register.verification_timeout')}{Style.RESET_ALL}") print(f"{Fore.RED}{translator.get('register.verification_timeout')}{Style.RESET_ALL}")
@@ -596,12 +470,12 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
if translator: if translator:
print(f"{Fore.CYAN}{translator.get('register.try_get_code', attempt=attempt + 1, time=remaining_time)}{Style.RESET_ALL}") print(f"{Fore.CYAN}{translator.get('register.try_get_code', attempt=attempt + 1, time=remaining_time)}{Style.RESET_ALL}")
# 刷新邮箱 # Refresh email
email_tab.refresh_inbox() email_tab.refresh_inbox()
time.sleep(retry_interval) # 使用 get_random_wait_time time.sleep(retry_interval) # Use get_random_wait_time
if verification_code: if verification_code:
# 在注册页面填写验证码 # Fill verification code in registration page
for i, digit in enumerate(verification_code): for i, digit in enumerate(verification_code):
browser_tab.ele(f"@data-index={i}").input(digit) browser_tab.ele(f"@data-index={i}").input(digit)
time.sleep(get_random_wait_time(config, 'verification_code_input')) time.sleep(get_random_wait_time(config, 'verification_code_input'))
@@ -610,19 +484,19 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}") print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}")
time.sleep(get_random_wait_time(config, 'verification_success_wait')) time.sleep(get_random_wait_time(config, 'verification_success_wait'))
# 处理最后一次 Turnstile 验证 # Handle last Turnstile verification
if handle_turnstile(browser_tab, config, translator): if handle_turnstile(browser_tab, config, translator):
if translator: if translator:
print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}") print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}")
time.sleep(get_random_wait_time(config, 'verification_retry_wait')) time.sleep(get_random_wait_time(config, 'verification_retry_wait'))
# 直接访问设置页面 # Visit settings page
if translator: if translator:
print(f"{Fore.CYAN}{translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}") print(f"{Fore.CYAN}{translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}")
browser_tab.get("https://www.cursor.com/settings") browser_tab.get("https://www.cursor.com/settings")
time.sleep(get_random_wait_time(config, 'settings_page_load_wait')) time.sleep(get_random_wait_time(config, 'settings_page_load_wait'))
# 直接返回成功,让 cursor_register.py 处理账户信息获取 # Return success directly, let cursor_register.py handle account information acquisition
return True, browser_tab return True, browser_tab
else: else:
@@ -638,58 +512,58 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
return False, None return False, None
def handle_sign_in(browser_tab, email, password, translator=None): def handle_sign_in(browser_tab, email, password, translator=None):
"""处理登录流程""" """Handle login process"""
try: try:
# 检查是否在登录页面 # Check if on login page
sign_in_header = browser_tab.ele('xpath://h1[contains(text(), "Sign in")]') sign_in_header = browser_tab.ele('xpath://h1[contains(text(), "Sign in")]')
if not sign_in_header: if not sign_in_header:
return True # 如果不是登录页面,说明已经登录成功 return True # If not on login page, it means login is successful
print(f"{Fore.CYAN}检测到登录页面,开始登录...{Style.RESET_ALL}") print(f"{Fore.CYAN}检测到登录页面,开始登录...{Style.RESET_ALL}")
# 填写邮箱 # Fill email
email_input = browser_tab.ele('@name=email') email_input = browser_tab.ele('@name=email')
if email_input: if email_input:
email_input.input(email) email_input.input(email)
time.sleep(1) time.sleep(1)
# 点击 Continue # Click Continue
continue_button = browser_tab.ele('xpath://button[contains(@class, "BrandedButton") and text()="Continue"]') continue_button = browser_tab.ele('xpath://button[contains(@class, "BrandedButton") and text()="Continue"]')
if continue_button: if continue_button:
continue_button.click() continue_button.click()
time.sleep(2) time.sleep(2)
# 处理 Turnstile 验证 # Handle Turnstile verification
if handle_turnstile(browser_tab, translator): if handle_turnstile(browser_tab, translator):
# 填写密码 # Fill password
password_input = browser_tab.ele('@name=password') password_input = browser_tab.ele('@name=password')
if password_input: if password_input:
password_input.input(password) password_input.input(password)
time.sleep(1) time.sleep(1)
# 点击 Sign in # Click Sign in
sign_in_button = browser_tab.ele('xpath://button[@name="intent" and @value="password"]') sign_in_button = browser_tab.ele('xpath://button[@name="intent" and @value="password"]')
if sign_in_button: if sign_in_button:
sign_in_button.click() sign_in_button.click()
time.sleep(2) time.sleep(2)
# 处理最后一次 Turnstile 验证 # Handle last Turnstile verification
if handle_turnstile(browser_tab, translator): if handle_turnstile(browser_tab, translator):
print(f"{Fore.GREEN}登录成功!{Style.RESET_ALL}") print(f"{Fore.GREEN}Login successful!{Style.RESET_ALL}")
time.sleep(3) time.sleep(3)
return True return True
print(f"{Fore.RED}登录失败{Style.RESET_ALL}") print(f"{Fore.RED}Login failed{Style.RESET_ALL}")
return False return False
except Exception as e: except Exception as e:
print(f"{Fore.RED}登录过程出错: {str(e)}{Style.RESET_ALL}") print(f"{Fore.RED}Login process error: {str(e)}{Style.RESET_ALL}")
return False return False
def main(email=None, password=None, first_name=None, last_name=None, email_tab=None, controller=None, translator=None): def main(email=None, password=None, first_name=None, last_name=None, email_tab=None, controller=None, translator=None):
"""主函数,可以接收账号信息、邮箱标签页和翻译器""" """Main function, can receive account information, email tab, and translator"""
global _translator global _translator
_translator = translator # 保存到全局变量 _translator = translator # Save to global variable
signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler) signal.signal(signal.SIGTERM, signal_handler)
@@ -701,62 +575,59 @@ def main(email=None, password=None, first_name=None, last_name=None, email_tab=N
if translator: if translator:
print(f"{Fore.CYAN}🚀 {translator.get('register.browser_started')}{Style.RESET_ALL}") print(f"{Fore.CYAN}🚀 {translator.get('register.browser_started')}{Style.RESET_ALL}")
# 访问注册页面 # Visit registration page
url = "https://authenticator.cursor.sh/sign-up" url = "https://authenticator.cursor.sh/sign-up"
if translator:
print(f"\n{Fore.CYAN}{translator.get('register.visiting_url')}: {url}{Style.RESET_ALL}")
# 访问页面 # Visit page
simulate_human_input(page, url, config, translator) simulate_human_input(page, url, config, translator)
if translator: if translator:
print(f"{Fore.CYAN}{translator.get('register.waiting_for_page_load')}{Style.RESET_ALL}") print(f"{Fore.CYAN}🔄 {translator.get('register.waiting_for_page_load')}{Style.RESET_ALL}")
time.sleep(get_random_wait_time(config, 'page_load_wait')) time.sleep(get_random_wait_time(config, 'page_load_wait'))
# 如果没有提供账号信息,则生成随机信息 # If account information is not provided, generate random information
if not all([email, password, first_name, last_name]): if not all([email, password, first_name, last_name]):
first_name = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=6)).capitalize() first_name = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=6)).capitalize()
last_name = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=6)).capitalize() last_name = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=6)).capitalize()
email = f"{first_name.lower()}{random.randint(100,999)}@example.com" email = f"{first_name.lower()}{random.randint(100,999)}@example.com"
password = generate_password() password = generate_password()
# 保存账号信息 # Save account information
with open('test_accounts.txt', 'a', encoding='utf-8') as f: with open('test_accounts.txt', 'a', encoding='utf-8') as f:
f.write(f"\n{'='*50}\n") f.write(f"\n{'='*50}\n")
f.write(f"Email: {email}\n") f.write(f"Email: {email}\n")
f.write(f"Password: {password}\n") f.write(f"Password: {password}\n")
f.write(f"{'='*50}\n") f.write(f"{'='*50}\n")
# 填写表单 # Fill form
if fill_signup_form(page, first_name, last_name, email, config, translator): if fill_signup_form(page, first_name, last_name, email, config, translator):
if translator: if translator:
print(f"\n{Fore.GREEN}{translator.get('register.form_submitted')}{Style.RESET_ALL}") print(f"\n{Fore.GREEN}{translator.get('register.form_submitted')}{Style.RESET_ALL}")
# 处理第一次 Turnstile 验证 # Handle first Turnstile verification
if handle_turnstile(page, config, translator): if handle_turnstile(page, config, translator):
if translator: if translator:
print(f"\n{Fore.GREEN}{translator.get('register.first_verification_passed')}{Style.RESET_ALL}") print(f"\n{Fore.GREEN}{translator.get('register.first_verification_passed')}{Style.RESET_ALL}")
# 填写密码 # Fill password
if fill_password(page, password, config, translator): if fill_password(page, password, config, translator):
if translator: if translator:
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_second_verification')}{Style.RESET_ALL}") print(f"\n{Fore.CYAN}🔄 {translator.get('register.waiting_for_second_verification')}{Style.RESET_ALL}")
time.sleep(2)
# Handle second Turnstile verification
# 处理第二次 Turnstile 验证
if handle_turnstile(page, config, translator): if handle_turnstile(page, config, translator):
if translator: if translator:
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}") print(f"\n{Fore.CYAN}🔄 {translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
if handle_verification_code(page, email_tab, controller, email, password, config, translator): if handle_verification_code(page, email_tab, controller, config, translator):
success = True success = True
return True, page return True, page
else: else:
print(f"\n{Fore.RED} {translator.get('register.verification_code_processing_failed') if translator else '验证码处理失败'}{Style.RESET_ALL}") print(f"\n{Fore.RED} {translator.get('register.verification_code_processing_failed') if translator else 'Verification code processing failed'}{Style.RESET_ALL}")
else: else:
print(f"\n{Fore.RED} {translator.get('register.second_verification_failed') if translator else '第二次验证失败'}{Style.RESET_ALL}") print(f"\n{Fore.RED} {translator.get('register.second_verification_failed') if translator else 'Second verification failed'}{Style.RESET_ALL}")
else: else:
print(f"\n{Fore.RED} {translator.get('register.second_verification_failed') if translator else '第二次验证失败'}{Style.RESET_ALL}") print(f"\n{Fore.RED} {translator.get('register.second_verification_failed') if translator else 'Second verification failed'}{Style.RESET_ALL}")
else: else:
print(f"\n{Fore.RED} {translator.get('register.first_verification_failed') if translator else '第一次验证失败'}{Style.RESET_ALL}") print(f"\n{Fore.RED} {translator.get('register.first_verification_failed') if translator else 'First verification failed'}{Style.RESET_ALL}")
return False, None return False, None
@@ -764,7 +635,7 @@ def main(email=None, password=None, first_name=None, last_name=None, email_tab=N
print(f"发生错误: {e}") print(f"发生错误: {e}")
return False, None return False, None
finally: finally:
if page and not success: # 只在失败时清理 if page and not success: # Only clean up when failed
try: try:
page.quit() page.quit()
except: except:
@@ -772,4 +643,4 @@ def main(email=None, password=None, first_name=None, last_name=None, email_tab=N
cleanup_chrome_processes(translator) cleanup_chrome_processes(translator)
if __name__ == "__main__": if __name__ == "__main__":
main() # 直接运行时不传参数,使用随机生成的信息 main() # Run without parameters, use randomly generated information

View File

@@ -263,7 +263,7 @@ class NewTempEmail:
return False return False
def check_for_cursor_email(self): def check_for_cursor_email(self):
"""检查是否有 Cursor 的验证邮件""" """Check if there is a Cursor verification email"""
try: try:
# Use API to get email list # Use API to get email list
headers = {"Authorization": f"Bearer {self.token}"} headers = {"Authorization": f"Bearer {self.token}"}

View File

@@ -13,6 +13,7 @@ from typing import Tuple
import configparser import configparser
from new_signup import get_user_documents_path from new_signup import get_user_documents_path
import traceback import traceback
from config import get_config
# Initialize colorama # Initialize colorama
init() init()
@@ -31,7 +32,7 @@ def get_cursor_paths(translator=None) -> Tuple[str, str]:
""" Get Cursor related paths""" """ Get Cursor related paths"""
system = platform.system() system = platform.system()
# 讀取配置文件 # Read config file
config = configparser.ConfigParser() config = configparser.ConfigParser()
config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip") config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip")
config_file = os.path.join(config_dir, "config.ini") config_file = os.path.join(config_dir, "config.ini")
@@ -39,9 +40,9 @@ def get_cursor_paths(translator=None) -> Tuple[str, str]:
if not os.path.exists(config_file): if not os.path.exists(config_file):
raise OSError(translator.get('reset.config_not_found') if translator else "找不到配置文件") raise OSError(translator.get('reset.config_not_found') if translator else "找不到配置文件")
config.read(config_file) config.read(config_file, encoding='utf-8') # Specify encoding
# 根據系統獲取路徑 # Get path based on system
if system == "Darwin": if system == "Darwin":
section = 'MacPaths' section = 'MacPaths'
elif system == "Windows": elif system == "Windows":
@@ -62,7 +63,7 @@ def get_cursor_paths(translator=None) -> Tuple[str, str]:
pkg_path = os.path.join(base_path, "package.json") pkg_path = os.path.join(base_path, "package.json")
main_path = os.path.join(base_path, "out/main.js") main_path = os.path.join(base_path, "out/main.js")
# 檢查文件是否存在 # Check if files exist
if not os.path.exists(pkg_path): if not os.path.exists(pkg_path):
raise OSError(translator.get('reset.package_not_found', path=pkg_path) if translator else f"找不到 package.json: {pkg_path}") raise OSError(translator.get('reset.package_not_found', path=pkg_path) if translator else f"找不到 package.json: {pkg_path}")
if not os.path.exists(main_path): if not os.path.exists(main_path):
@@ -186,7 +187,7 @@ def check_cursor_version(translator) -> bool:
with open(pkg_path, "r", encoding="utf-8") as f: with open(pkg_path, "r", encoding="utf-8") as f:
data = json.load(f) data = json.load(f)
except UnicodeDecodeError: except UnicodeDecodeError:
# 如果 UTF-8 讀取失敗,嘗試其他編碼 # If UTF-8 reading fails, try other encodings
with open(pkg_path, "r", encoding="latin-1") as f: with open(pkg_path, "r", encoding="latin-1") as f:
data = json.load(f) data = json.load(f)
@@ -205,15 +206,15 @@ def check_cursor_version(translator) -> bool:
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.found_version', version=version)}{Style.RESET_ALL}") print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.found_version', version=version)}{Style.RESET_ALL}")
# 檢查版本格式 # Check version format
if not re.match(r"^\d+\.\d+\.\d+$", version): if not re.match(r"^\d+\.\d+\.\d+$", version):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.invalid_version_format', version=version)}{Style.RESET_ALL}") print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.invalid_version_format', version=version)}{Style.RESET_ALL}")
return False return False
# 比較版本 # Compare versions
try: try:
current = tuple(map(int, version.split("."))) current = tuple(map(int, version.split(".")))
min_ver = (0, 45, 0) # 直接使用元組而不是字符串 min_ver = (0, 45, 0) # Use tuple directly instead of string
if current >= min_ver: if current >= min_ver:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.version_check_passed', version=version, min_version='0.45.0')}{Style.RESET_ALL}") print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.version_check_passed', version=version, min_version='0.45.0')}{Style.RESET_ALL}")
@@ -408,7 +409,7 @@ class MachineIDResetter:
if not os.path.exists(config_file): if not os.path.exists(config_file):
raise FileNotFoundError(f"Config file not found: {config_file}") raise FileNotFoundError(f"Config file not found: {config_file}")
config.read(config_file) config.read(config_file, encoding='utf-8')
# Check operating system # Check operating system
if sys.platform == "win32": # Windows if sys.platform == "win32": # Windows
@@ -444,7 +445,7 @@ class MachineIDResetter:
elif sys.platform == "linux": # Linux elif sys.platform == "linux": # Linux
if not config.has_section('LinuxPaths'): if not config.has_section('LinuxPaths'):
config.add_section('LinuxPaths') config.add_section('LinuxPaths')
# 获取实际用户的主目录 # Get actual user's home directory
sudo_user = os.environ.get('SUDO_USER') sudo_user = os.environ.get('SUDO_USER')
actual_home = f"/home/{sudo_user}" if sudo_user else os.path.expanduser("~") actual_home = f"/home/{sudo_user}" if sudo_user else os.path.expanduser("~")
@@ -690,7 +691,9 @@ class MachineIDResetter:
return False return False
def run(translator=None): def run(translator=None):
"""Convenient function for directly calling the reset function""" config = get_config(translator)
if not config:
return False
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}") print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['RESET']} {translator.get('reset.title')}{Style.RESET_ALL}") print(f"{Fore.CYAN}{EMOJI['RESET']} {translator.get('reset.title')}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{'='*50}{Style.RESET_ALL}") print(f"{Fore.CYAN}{'='*50}{Style.RESET_ALL}")

View File

@@ -134,7 +134,7 @@ install_cursor_free_vip() {
echo -e "${RED}❌ New download link does not exist${NC}" echo -e "${RED}❌ New download link does not exist${NC}"
exit 1 exit 1
fi fi
} elif [[ "$OS" == "linux_x64" || "$OS" == "linux_arm64" ]]; then elif [[ "$OS" == "linux_x64" || "$OS" == "linux_arm64" ]]; then
OS="linux" OS="linux"
binary_name="CursorFreeVIP_${VERSION}_${OS}" binary_name="CursorFreeVIP_${VERSION}_${OS}"
download_url="https://github.com/yeongpin/cursor-free-vip/releases/download/v${VERSION}/${binary_name}" download_url="https://github.com/yeongpin/cursor-free-vip/releases/download/v${VERSION}/${binary_name}"
@@ -144,9 +144,9 @@ install_cursor_free_vip() {
echo -e "${RED}❌ New download link does not exist${NC}" echo -e "${RED}❌ New download link does not exist${NC}"
exit 1 exit 1
fi fi
} else { else
exit 1 exit 1
} fi
fi fi
# Download file # Download file

32
utils.py Normal file
View File

@@ -0,0 +1,32 @@
import os
import sys
import platform
def get_user_documents_path():
"""Get user documents path"""
if platform.system() == "Windows":
return os.path.expanduser("~\\Documents")
else:
return os.path.expanduser("~/Documents")
def get_default_chrome_path():
"""Get default Chrome path"""
if sys.platform == "win32":
return r"C:\Program Files\Google\Chrome\Application\chrome.exe"
elif sys.platform == "darwin":
return "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
else:
return "/usr/bin/google-chrome"
def get_linux_cursor_path():
"""Get Linux Cursor path"""
possible_paths = [
"/opt/Cursor/resources/app",
"/usr/share/cursor/resources/app",
"/opt/cursor-bin/resources/app",
"/usr/lib/cursor/resources/app",
os.path.expanduser("~/.local/share/cursor/resources/app")
]
# return the first path that exists
return next((path for path in possible_paths if os.path.exists(path)), possible_paths[0])