mirror of
https://git.axenov.dev/mirrors/cursor-free-vip.git
synced 2026-01-03 09:19:27 +03:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe3e27561b | ||
|
|
bf2bea71eb | ||
|
|
77a61647dd | ||
|
|
813dd4431e | ||
|
|
d7116b8cf3 | ||
|
|
f5a7acc4e3 | ||
|
|
479933844a | ||
|
|
93046d7f03 | ||
|
|
e7ca31b710 | ||
|
|
87b99b0d16 | ||
|
|
e983b6f560 | ||
|
|
21ca7ab24f | ||
|
|
e7468644a4 | ||
|
|
2bca7d7d14 | ||
|
|
040c5f5836 | ||
|
|
4a86bbeeb4 | ||
|
|
68b7888a83 | ||
|
|
78dee025a7 | ||
|
|
17c2b4b243 | ||
|
|
2acb271f19 | ||
|
|
b688b67c26 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -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.4.01'
|
default: '1.4.07'
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|||||||
49
.gitignore
vendored
49
.gitignore
vendored
@@ -1,8 +1,47 @@
|
|||||||
cursor_accounts.txt
|
__pycache__
|
||||||
/venv
|
server/
|
||||||
/__pycache__
|
venv/
|
||||||
dist
|
check_license.py
|
||||||
build
|
cursor_modifier.py
|
||||||
|
reset_machine.py
|
||||||
|
Run_Venv.bat
|
||||||
|
token_monitor.py
|
||||||
|
get_mac.py
|
||||||
|
.gitignore
|
||||||
|
build.bat
|
||||||
|
build.mac.command
|
||||||
|
build.py
|
||||||
|
build.sh
|
||||||
|
ENV/
|
||||||
|
|
||||||
install.bat
|
install.bat
|
||||||
run.bat
|
run.bat
|
||||||
|
|
||||||
temp_account_info.txt
|
temp_account_info.txt
|
||||||
|
|
||||||
|
.env copy
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
*.spec2
|
||||||
|
|
||||||
|
credentials.txt
|
||||||
|
cursor_accounts.txt
|
||||||
|
recaptcha.py
|
||||||
|
install_requirements.bat
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Project specific
|
||||||
|
*.log
|
||||||
|
*.db
|
||||||
|
*.sqlite3
|
||||||
|
|||||||
22
CHANGELOG.md
22
CHANGELOG.md
@@ -1,5 +1,27 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## v1.5.01
|
||||||
|
1. Add: Check Latest Version | 增加檢查最新版本
|
||||||
|
2. Add: Update Command | 增加更新命令
|
||||||
|
|
||||||
|
## v1.4.08
|
||||||
|
1. Add: Print Some Account Info | 增加打印一些賬號信息
|
||||||
|
|
||||||
|
## v1.4.07
|
||||||
|
1. Add Removed break statements after each operation | 修改結束event後的break暫停應用
|
||||||
|
2. Added print_menu() calls to show the menu again | 添加print_menu()調用以再次顯示菜單
|
||||||
|
3. Updated error handling to show menu instead of exiting | 更新錯誤處理以顯示菜單而不是退出
|
||||||
|
|
||||||
|
## v1.4.06
|
||||||
|
|
||||||
|
1. Add: Blocked Domains Loaded | 增加被屏蔽的域名加載
|
||||||
|
2. Fix: Cleanup Error | 修復清理進程時出錯
|
||||||
|
3. Fix: Blocked Domains Loaded Error | 修復被屏蔽的域名加載錯誤
|
||||||
|
4. Fix: Available Domains Loaded Error | 修復可用域名加載錯誤
|
||||||
|
5. Fix: Domains Filtered Error | 修復過濾後剩餘域名錯誤
|
||||||
|
6. Fix: Domains Excluded Error | 修復排除域名錯誤
|
||||||
|
|
||||||
|
|
||||||
## v1.4.05
|
## v1.4.05
|
||||||
|
|
||||||
1. Fix: macOS Language Detection | 修復macOS語言檢測
|
1. Fix: macOS Language Detection | 修復macOS語言檢測
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# ➤ Cursor Free VIP
|
# ➤ Cursor Free VIP
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./images/logo.png" alt="Cursor Pro Logo" width="200"/>
|
<img src="./images/logo.png" alt="Cursor Pro Logo" width="200" style="border-radius: 6px;"/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
@@ -19,7 +19,7 @@ This is a tool to automatically register , support Windows and macOS systems, co
|
|||||||
這是一個自動化工具,自動註冊 ,支持 Windows 和 macOS 系統,完成Auth驗證,重置Cursor的配置。
|
這是一個自動化工具,自動註冊 ,支持 Windows 和 macOS 系統,完成Auth驗證,重置Cursor的配置。
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./images/pronew_2025-02-13_15-01-32.png" alt="new" width="400"/><br>
|
<img src="./images/new_2025-02-27_10-42-44.png" alt="new" width="400" style="border-radius: 6px;"/><br>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
##### If you dont have google chrome , you can download it from [here](https://www.google.com/intl/en_pk/chrome/)
|
##### If you dont have google chrome , you can download it from [here](https://www.google.com/intl/en_pk/chrome/)
|
||||||
|
|||||||
3
block_domain.txt
Normal file
3
block_domain.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
oakon.com
|
||||||
|
famamail.com
|
||||||
|
2925.com
|
||||||
@@ -26,6 +26,10 @@ class CursorAuth:
|
|||||||
self.db_path = os.path.join(
|
self.db_path = os.path.join(
|
||||||
os.getenv("APPDATA"), "Cursor", "User", "globalStorage", "state.vscdb"
|
os.getenv("APPDATA"), "Cursor", "User", "globalStorage", "state.vscdb"
|
||||||
)
|
)
|
||||||
|
elif os.name =='posix':
|
||||||
|
self.db_path = os.path.expanduser(
|
||||||
|
"~/.config/Cursor/User/globalStorage/state.vscdb"
|
||||||
|
)
|
||||||
else: # macOS
|
else: # macOS
|
||||||
self.db_path = os.path.expanduser(
|
self.db_path = os.path.expanduser(
|
||||||
"~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
|
"~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ class CursorRegistration:
|
|||||||
self.password = self._generate_password()
|
self.password = self._generate_password()
|
||||||
self.first_name = self._generate_name()
|
self.first_name = self._generate_name()
|
||||||
self.last_name = self._generate_name()
|
self.last_name = self._generate_name()
|
||||||
|
print(f"Password: {self.password}\n")
|
||||||
|
print(f"First Name: {self.first_name}\n")
|
||||||
|
print(f"Last Name: {self.last_name}\n")
|
||||||
|
|
||||||
def _generate_password(self, length=12):
|
def _generate_password(self, length=12):
|
||||||
"""Generate Random Password"""
|
"""Generate Random Password"""
|
||||||
@@ -78,6 +81,7 @@ class CursorRegistration:
|
|||||||
|
|
||||||
# 保存邮箱地址
|
# 保存邮箱地址
|
||||||
self.email_address = email_address
|
self.email_address = email_address
|
||||||
|
print(f"Email Address: {self.email_address}\n")
|
||||||
self.email_tab = self.temp_email # 传递 NewTempEmail 实例
|
self.email_tab = self.temp_email # 传递 NewTempEmail 实例
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -149,6 +153,7 @@ class CursorRegistration:
|
|||||||
if usage_ele:
|
if usage_ele:
|
||||||
total_usage = usage_ele.text.split("/")[-1].strip()
|
total_usage = usage_ele.text.split("/")[-1].strip()
|
||||||
|
|
||||||
|
print(f"Total Usage: {total_usage}\n")
|
||||||
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.get_token')}...{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.get_token')}...{Style.RESET_ALL}")
|
||||||
max_attempts = 30
|
max_attempts = 30
|
||||||
retry_interval = 2
|
retry_interval = 2
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ class CursorRegistration:
|
|||||||
self.password = self._generate_password()
|
self.password = self._generate_password()
|
||||||
self.first_name = self._generate_name()
|
self.first_name = self._generate_name()
|
||||||
self.last_name = self._generate_name()
|
self.last_name = self._generate_name()
|
||||||
|
print(f"Password: {self.password}\n")
|
||||||
|
print(f"First Name: {self.first_name}\n")
|
||||||
|
print(f"Last Name: {self.last_name}\n")
|
||||||
|
|
||||||
def _generate_password(self, length=12):
|
def _generate_password(self, length=12):
|
||||||
"""Generate Random Password"""
|
"""Generate Random Password"""
|
||||||
@@ -70,6 +73,7 @@ class CursorRegistration:
|
|||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.invalid_email') if self.translator else '无效的邮箱地址'}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.invalid_email') if self.translator else '无效的邮箱地址'}{Style.RESET_ALL}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
print(f"Email Address: {self.email_address}\n")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -155,6 +159,7 @@ class CursorRegistration:
|
|||||||
if usage_ele:
|
if usage_ele:
|
||||||
total_usage = usage_ele.text.split("/")[-1].strip()
|
total_usage = usage_ele.text.split("/")[-1].strip()
|
||||||
|
|
||||||
|
print(f"Total Usage: {total_usage}\n")
|
||||||
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.get_token')}...{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.get_token')}...{Style.RESET_ALL}")
|
||||||
max_attempts = 30
|
max_attempts = 30
|
||||||
retry_interval = 2
|
retry_interval = 2
|
||||||
|
|||||||
BIN
images/new_2025-02-27_10-42-44.png
Normal file
BIN
images/new_2025-02-27_10-42-44.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 116 KiB |
@@ -203,7 +203,23 @@
|
|||||||
"verification_code_found": "Verification Code Found",
|
"verification_code_found": "Verification Code Found",
|
||||||
"verification_code_not_found": "Verification Code Not Found",
|
"verification_code_not_found": "Verification Code Not Found",
|
||||||
"verification_code_error": "Verification Code Error: {error}",
|
"verification_code_error": "Verification Code Error: {error}",
|
||||||
"address": "Email Address"
|
"address": "Email Address",
|
||||||
|
"all_domains_blocked": "All Domains Blocked, Switching Service",
|
||||||
|
"no_available_domains_after_filtering": "No Available Domains After Filtering",
|
||||||
|
"switching_service": "Switching to {service} Service",
|
||||||
|
"domains_list_error": "Failed to Get Domains List: {error}",
|
||||||
|
"failed_to_get_available_domains": "Failed to Get Available Domains",
|
||||||
|
"domains_excluded": "Domains Excluded: {domains}",
|
||||||
|
"failed_to_create_account": "Failed to Create Account",
|
||||||
|
"account_creation_error": "Account Creation Error: {error}",
|
||||||
|
"blocked_domains": "Blocked Domains: {domains}",
|
||||||
|
"blocked_domains_loaded": "Blocked Domains Loaded: {count}",
|
||||||
|
"blocked_domains_loaded_error": "Blocked Domains Loaded Error: {error}",
|
||||||
|
"blocked_domains_loaded_success": "Blocked Domains Loaded Successfully",
|
||||||
|
"blocked_domains_loaded_timeout": "Blocked Domains Loaded Timeout: {timeout}s",
|
||||||
|
"blocked_domains_loaded_timeout_error": "Blocked Domains Loaded Timeout Error: {error}",
|
||||||
|
"available_domains_loaded": "Available Domains Loaded: {count}",
|
||||||
|
"domains_filtered": "Domains Filtered: {count}"
|
||||||
},
|
},
|
||||||
"update": {
|
"update": {
|
||||||
"title": "Disable Cursor Auto Update",
|
"title": "Disable Cursor Auto Update",
|
||||||
@@ -217,5 +233,13 @@
|
|||||||
"directory_removed": "Directory Removed",
|
"directory_removed": "Directory Removed",
|
||||||
"creating_block_file": "Creating Block File",
|
"creating_block_file": "Creating Block File",
|
||||||
"block_file_created": "Block File Created"
|
"block_file_created": "Block File Created"
|
||||||
|
},
|
||||||
|
"updater": {
|
||||||
|
"checking": "Checking for updates...",
|
||||||
|
"new_version_available": "New version available! (Current: {current}, Latest: {latest})",
|
||||||
|
"updating": "Updating to the latest version. The program will restart automatically.",
|
||||||
|
"up_to_date": "You are using the latest version.",
|
||||||
|
"check_failed": "Failed to check for updates: {error}",
|
||||||
|
"continue_anyway": "Continuing with current version..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,7 +200,23 @@
|
|||||||
"verification_code_found": "找到验证码",
|
"verification_code_found": "找到验证码",
|
||||||
"verification_code_not_found": "未找到验证码",
|
"verification_code_not_found": "未找到验证码",
|
||||||
"verification_code_error": "验证码错误: {error}",
|
"verification_code_error": "验证码错误: {error}",
|
||||||
"address": "邮箱地址"
|
"address": "邮箱地址",
|
||||||
|
"all_domains_blocked": "所有域名都被屏蔽了,切换服务",
|
||||||
|
"no_available_domains_after_filtering": "过滤后没有可用域名",
|
||||||
|
"switching_service": "切换到 {service} 服务",
|
||||||
|
"domains_list_error": "获取域名列表失败: {error}",
|
||||||
|
"failed_to_get_available_domains": "获取可用域名失败",
|
||||||
|
"blocked_domains_loaded": "加载了 {count} 个被屏蔽的域名",
|
||||||
|
"domains_excluded": "排除了 {domains} 个被屏蔽的域名",
|
||||||
|
"failed_to_create_account": "创建账户失败",
|
||||||
|
"account_creation_error": "账户创建错误: {error}",
|
||||||
|
"blocked_domains": "被屏蔽的域名: {domains}",
|
||||||
|
"blocked_domains_loaded_error": "加载被屏蔽的域名失败: {error}",
|
||||||
|
"blocked_domains_loaded_success": "加载被屏蔽的域名成功",
|
||||||
|
"blocked_domains_loaded_timeout": "加载被屏蔽的域名超时: {timeout}秒",
|
||||||
|
"blocked_domains_loaded_timeout_error": "加载被屏蔽的域名超时错误: {error}",
|
||||||
|
"available_domains_loaded": "获取到 {count} 个可用域名",
|
||||||
|
"domains_filtered": "过滤后剩餘 {count} 個可用域名"
|
||||||
},
|
},
|
||||||
"update": {
|
"update": {
|
||||||
"title": "禁用 Cursor 自动更新",
|
"title": "禁用 Cursor 自动更新",
|
||||||
@@ -214,5 +230,13 @@
|
|||||||
"directory_removed": "目录已删除",
|
"directory_removed": "目录已删除",
|
||||||
"creating_block_file": "创建阻止文件",
|
"creating_block_file": "创建阻止文件",
|
||||||
"block_file_created": "阻止文件已创建"
|
"block_file_created": "阻止文件已创建"
|
||||||
|
},
|
||||||
|
"updater": {
|
||||||
|
"checking": "检查更新...",
|
||||||
|
"new_version_available": "有新版本可用! (当前版本: {current}, 最新版本: {latest})",
|
||||||
|
"updating": "正在更新到最新版本。程序将自动重启。",
|
||||||
|
"up_to_date": "您使用的是最新版本。",
|
||||||
|
"check_failed": "检查更新失败: {error}",
|
||||||
|
"continue_anyway": "继续使用当前版本..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,7 +181,23 @@
|
|||||||
"verification_code_found": "找到驗證碼",
|
"verification_code_found": "找到驗證碼",
|
||||||
"verification_code_not_found": "未找到驗證碼",
|
"verification_code_not_found": "未找到驗證碼",
|
||||||
"verification_code_error": "驗證碼錯誤: {error}",
|
"verification_code_error": "驗證碼錯誤: {error}",
|
||||||
"address": "郵箱地址"
|
"address": "郵箱地址",
|
||||||
|
"all_domains_blocked": "所有域名都被屏蔽了,切換服務",
|
||||||
|
"no_available_domains_after_filtering": "過濾後沒有可用域名",
|
||||||
|
"switching_service": "切換到 {service} 服務",
|
||||||
|
"domains_list_error": "獲取域名列表失敗: {error}",
|
||||||
|
"failed_to_get_available_domains": "獲取可用域名失敗",
|
||||||
|
"domains_excluded": "排除的域名: {domains}",
|
||||||
|
"failed_to_create_account": "創建帳戶失敗",
|
||||||
|
"account_creation_error": "帳戶創建錯誤: {error}",
|
||||||
|
"blocked_domains": "被屏蔽的域名: {domains}",
|
||||||
|
"blocked_domains_loaded": "加載被屏蔽的域名: {domains}",
|
||||||
|
"blocked_domains_loaded_error": "加載被屏蔽的域名失敗: {error}",
|
||||||
|
"blocked_domains_loaded_success": "加載被屏蔽的域名成功",
|
||||||
|
"blocked_domains_loaded_timeout": "加載被屏蔽的域名超時: {timeout}秒",
|
||||||
|
"blocked_domains_loaded_timeout_error": "加載被屏蔽的域名超時錯誤: {error}",
|
||||||
|
"available_domains_loaded": "獲取到 {count} 個可用域名",
|
||||||
|
"domains_filtered": "過濾後剩餘 {count} 個可用域名"
|
||||||
},
|
},
|
||||||
"update": {
|
"update": {
|
||||||
"title": "禁用 Cursor 自动更新",
|
"title": "禁用 Cursor 自动更新",
|
||||||
@@ -195,5 +211,13 @@
|
|||||||
"directory_removed": "目錄已刪除",
|
"directory_removed": "目錄已刪除",
|
||||||
"creating_block_file": "創建阻止文件",
|
"creating_block_file": "創建阻止文件",
|
||||||
"block_file_created": "阻止文件已創建"
|
"block_file_created": "阻止文件已創建"
|
||||||
|
},
|
||||||
|
"updater": {
|
||||||
|
"checking": "檢查更新...",
|
||||||
|
"new_version_available": "有新版本可用! (當前版本: {current}, 最新版本: {latest})",
|
||||||
|
"updating": "正在更新到最新版本。程序將自動重啟。",
|
||||||
|
"up_to_date": "您使用的是最新版本。",
|
||||||
|
"check_failed": "檢查更新失敗: {error}",
|
||||||
|
"continue_anyway": "繼續使用當前版本..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
50
main.py
50
main.py
@@ -3,10 +3,12 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
from logo import print_logo
|
from logo import print_logo, version
|
||||||
from colorama import Fore, Style, init
|
from colorama import Fore, Style, init
|
||||||
import locale
|
import locale
|
||||||
import platform
|
import platform
|
||||||
|
import requests
|
||||||
|
import subprocess
|
||||||
|
|
||||||
# 只在 Windows 系统上导入 windll
|
# 只在 Windows 系统上导入 windll
|
||||||
if platform.system() == 'Windows':
|
if platform.system() == 'Windows':
|
||||||
@@ -203,8 +205,39 @@ def select_language():
|
|||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def check_latest_version():
|
||||||
|
"""Check if current version matches the latest release version"""
|
||||||
|
try:
|
||||||
|
print(f"\n{Fore.CYAN}{EMOJI['UPDATE']} {translator.get('updater.checking')}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# Get latest version from GitHub API with timeout
|
||||||
|
response = requests.get("https://api.github.com/repos/yeongpin/cursor-free-vip/releases/latest", timeout=5)
|
||||||
|
latest_version = response.json()["tag_name"].lstrip('v')
|
||||||
|
|
||||||
|
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}")
|
||||||
|
|
||||||
|
# Execute update command based on platform
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
update_command = 'irm https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/scripts/install.ps1 | iex'
|
||||||
|
subprocess.run(['powershell', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', update_command], check=True)
|
||||||
|
else:
|
||||||
|
update_command = 'curl -fsSL https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/scripts/install.sh -o install.sh && chmod +x install.sh && ./install.sh'
|
||||||
|
subprocess.Popen(update_command, shell=True)
|
||||||
|
|
||||||
|
print(f"\n{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('updater.updating')}{Style.RESET_ALL}")
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('updater.up_to_date')}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('updater.check_failed', error=str(e))}{Style.RESET_ALL}")
|
||||||
|
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('updater.continue_anyway')}{Style.RESET_ALL}")
|
||||||
|
return # Continue with the program instead of blocking
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
print_logo()
|
print_logo()
|
||||||
|
check_latest_version() # Add version check before showing menu
|
||||||
print_menu()
|
print_menu()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
@@ -218,19 +251,19 @@ def main():
|
|||||||
elif choice == "1":
|
elif choice == "1":
|
||||||
import reset_machine_manual
|
import reset_machine_manual
|
||||||
reset_machine_manual.run(translator)
|
reset_machine_manual.run(translator)
|
||||||
break
|
print_menu()
|
||||||
elif choice == "2":
|
elif choice == "2":
|
||||||
import cursor_register
|
import cursor_register
|
||||||
cursor_register.main(translator)
|
cursor_register.main(translator)
|
||||||
break
|
print_menu()
|
||||||
elif choice == "3":
|
elif choice == "3":
|
||||||
import cursor_register_manual
|
import cursor_register_manual
|
||||||
cursor_register_manual.main(translator)
|
cursor_register_manual.main(translator)
|
||||||
break
|
print_menu()
|
||||||
elif choice == "4":
|
elif choice == "4":
|
||||||
import quit_cursor
|
import quit_cursor
|
||||||
quit_cursor.quit_cursor(translator)
|
quit_cursor.quit_cursor(translator)
|
||||||
break
|
print_menu()
|
||||||
elif choice == "5":
|
elif choice == "5":
|
||||||
if select_language():
|
if select_language():
|
||||||
print_menu()
|
print_menu()
|
||||||
@@ -238,7 +271,7 @@ def main():
|
|||||||
elif choice == "6":
|
elif choice == "6":
|
||||||
import disable_auto_update
|
import disable_auto_update
|
||||||
disable_auto_update.run(translator)
|
disable_auto_update.run(translator)
|
||||||
break
|
print_menu()
|
||||||
else:
|
else:
|
||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
|
||||||
print_menu()
|
print_menu()
|
||||||
@@ -249,10 +282,7 @@ def main():
|
|||||||
return
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.error_occurred', error=str(e))}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.error_occurred', error=str(e))}{Style.RESET_ALL}")
|
||||||
break
|
print_menu()
|
||||||
|
|
||||||
print(f"\n{Fore.CYAN}{'═' * 50}{Style.RESET_ALL}")
|
|
||||||
input(f"{EMOJI['INFO']} {translator.get('menu.press_enter')}...{Style.RESET_ALL}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
127
new_tempemail.py
127
new_tempemail.py
@@ -23,6 +23,47 @@ class NewTempEmail:
|
|||||||
self.token = None
|
self.token = None
|
||||||
self.email = None
|
self.email = None
|
||||||
self.password = None
|
self.password = None
|
||||||
|
self.blocked_domains = self.get_blocked_domains()
|
||||||
|
|
||||||
|
def get_blocked_domains(self):
|
||||||
|
"""Get blocked domains list"""
|
||||||
|
try:
|
||||||
|
block_url = "https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/block_domain.txt"
|
||||||
|
response = requests.get(block_url, timeout=5)
|
||||||
|
if response.status_code == 200:
|
||||||
|
# Split text and remove empty lines
|
||||||
|
domains = [line.strip() for line in response.text.split('\n') if line.strip()]
|
||||||
|
if self.translator:
|
||||||
|
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.blocked_domains_loaded', count=len(domains))}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"{Fore.CYAN}ℹ️ 已加载 {len(domains)} 个被屏蔽的域名{Style.RESET_ALL}")
|
||||||
|
return domains
|
||||||
|
return []
|
||||||
|
except Exception as e:
|
||||||
|
if self.translator:
|
||||||
|
print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.blocked_domains_error', error=str(e))}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"{Fore.YELLOW}⚠️ 获取被屏蔽域名列表失败: {str(e)}{Style.RESET_ALL}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def exclude_blocked_domains(self, domains):
|
||||||
|
"""Exclude blocked domains"""
|
||||||
|
if not self.blocked_domains:
|
||||||
|
return domains
|
||||||
|
|
||||||
|
filtered_domains = []
|
||||||
|
for domain in domains:
|
||||||
|
if domain['domain'] not in self.blocked_domains:
|
||||||
|
filtered_domains.append(domain)
|
||||||
|
|
||||||
|
excluded_count = len(domains) - len(filtered_domains)
|
||||||
|
if excluded_count > 0:
|
||||||
|
if self.translator:
|
||||||
|
print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.domains_excluded', domains=excluded_count)}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"{Fore.YELLOW}⚠️ 已排除 {excluded_count} 个被屏蔽的域名{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
return filtered_domains
|
||||||
|
|
||||||
def _generate_credentials(self):
|
def _generate_credentials(self):
|
||||||
"""生成随机用户名和密码"""
|
"""生成随机用户名和密码"""
|
||||||
@@ -39,41 +80,111 @@ class NewTempEmail:
|
|||||||
print(f"{Fore.CYAN}ℹ️ 正在访问 {self.selected_service['name']}...{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ 正在访问 {self.selected_service['name']}...{Style.RESET_ALL}")
|
||||||
|
|
||||||
# 获取可用域名列表
|
# 获取可用域名列表
|
||||||
domains_response = requests.get(f"{self.api_url}/domains")
|
try:
|
||||||
|
domains_response = requests.get(f"{self.api_url}/domains", timeout=10)
|
||||||
if domains_response.status_code != 200:
|
if domains_response.status_code != 200:
|
||||||
raise Exception(f"{self.translator.get('email.failed_to_get_available_domains')}")
|
print(f"{Fore.RED}❌ {self.translator.get('email.domains_list_error', error=domains_response.status_code)}{Style.RESET_ALL}")
|
||||||
|
print(f"{Fore.RED}❌ {self.translator.get('email.domains_list_error', error=domains_response.text)}{Style.RESET_ALL}")
|
||||||
|
raise Exception(f"{self.translator.get('email.failed_to_get_available_domains') if self.translator else 'Failed to get available domains'}")
|
||||||
|
|
||||||
domains = domains_response.json()["hydra:member"]
|
domains = domains_response.json()["hydra:member"]
|
||||||
|
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.available_domains_loaded', count=len(domains))}{Style.RESET_ALL}")
|
||||||
|
|
||||||
if not domains:
|
if not domains:
|
||||||
raise Exception(f"{self.translator.get('email.no_available_domains')}")
|
raise Exception(f"{self.translator.get('email.no_available_domains') if self.translator else '没有可用域名'}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}❌ 获取域名列表时出错: {str(e)}{Style.RESET_ALL}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
# 排除被屏蔽的域名
|
||||||
|
try:
|
||||||
|
filtered_domains = self.exclude_blocked_domains(domains)
|
||||||
|
if self.translator:
|
||||||
|
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.domains_filtered', count=len(filtered_domains))}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"{Fore.CYAN}ℹ️ 过滤后剩余 {len(filtered_domains)} 个可用域名{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
if not filtered_domains:
|
||||||
|
if self.translator:
|
||||||
|
print(f"{Fore.RED}❌ {self.translator.get('email.all_domains_blocked')}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"{Fore.RED}❌ 所有域名都被屏蔽了,尝试切换服务{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# 切换到另一个服务
|
||||||
|
for service in self.services:
|
||||||
|
if service["api_url"] != self.api_url:
|
||||||
|
self.selected_service = service
|
||||||
|
self.api_url = service["api_url"]
|
||||||
|
if self.translator:
|
||||||
|
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.switching_service', service=service['name'])}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"{Fore.CYAN}ℹ️ 切换到 {service['name']} 服务{Style.RESET_ALL}")
|
||||||
|
return self.create_email() # 递归调用
|
||||||
|
|
||||||
|
raise Exception(f"{self.translator.get('email.no_available_domains_after_filtering') if self.translator else '过滤后没有可用域名'}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}❌ 过滤域名时出错: {str(e)}{Style.RESET_ALL}")
|
||||||
|
raise
|
||||||
|
|
||||||
# 生成随机用户名和密码
|
# 生成随机用户名和密码
|
||||||
|
try:
|
||||||
username, password = self._generate_credentials()
|
username, password = self._generate_credentials()
|
||||||
self.password = password
|
self.password = password
|
||||||
|
|
||||||
# 创建邮箱账户
|
# 创建邮箱账户
|
||||||
email = f"{username}@{domains[0]['domain']}"
|
selected_domain = filtered_domains[0]['domain']
|
||||||
|
email = f"{username}@{selected_domain}"
|
||||||
|
|
||||||
|
print(f"{Fore.CYAN}ℹ️ 尝试创建邮箱: {email}{Style.RESET_ALL}")
|
||||||
|
|
||||||
account_data = {
|
account_data = {
|
||||||
"address": email,
|
"address": email,
|
||||||
"password": password
|
"password": password
|
||||||
}
|
}
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}❌ 生成凭据时出错: {str(e)}{Style.RESET_ALL}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
# 创建账户
|
||||||
|
try:
|
||||||
|
create_response = requests.post(f"{self.api_url}/accounts", json=account_data, timeout=15)
|
||||||
|
|
||||||
create_response = requests.post(f"{self.api_url}/accounts", json=account_data)
|
|
||||||
if create_response.status_code != 201:
|
if create_response.status_code != 201:
|
||||||
raise Exception(f"{self.translator.get('email.failed_to_create_account')}")
|
print(f"{Fore.RED}❌ 创建账户失败: 状态码 {create_response.status_code}{Style.RESET_ALL}")
|
||||||
|
print(f"{Fore.RED}❌ 响应内容: {create_response.text}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# 如果是域名问题,尝试下一个域名
|
||||||
|
if len(filtered_domains) > 1 and ("domain" in create_response.text.lower() or "address" in create_response.text.lower()):
|
||||||
|
print(f"{Fore.YELLOW}⚠️ 尝试使用下一个可用域名...{Style.RESET_ALL}")
|
||||||
|
# 将当前域名添加到屏蔽列表
|
||||||
|
if selected_domain not in self.blocked_domains:
|
||||||
|
self.blocked_domains.append(selected_domain)
|
||||||
|
# 递归调用自己
|
||||||
|
return self.create_email()
|
||||||
|
|
||||||
|
raise Exception(f"{self.translator.get('email.failed_to_create_account') if self.translator else '创建账户失败'}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}❌ 创建账户时出错: {str(e)}{Style.RESET_ALL}")
|
||||||
|
raise
|
||||||
|
|
||||||
# 获取访问令牌
|
# 获取访问令牌
|
||||||
|
try:
|
||||||
token_data = {
|
token_data = {
|
||||||
"address": email,
|
"address": email,
|
||||||
"password": password
|
"password": password
|
||||||
}
|
}
|
||||||
|
|
||||||
token_response = requests.post(f"{self.api_url}/token", json=token_data)
|
token_response = requests.post(f"{self.api_url}/token", json=token_data, timeout=10)
|
||||||
if token_response.status_code != 200:
|
if token_response.status_code != 200:
|
||||||
raise Exception(f"{self.translator.get('email.failed_to_get_access_token')}")
|
print(f"{Fore.RED}❌ 获取令牌失败: 状态码 {token_response.status_code}{Style.RESET_ALL}")
|
||||||
|
print(f"{Fore.RED}❌ 响应内容: {token_response.text}{Style.RESET_ALL}")
|
||||||
|
raise Exception(f"{self.translator.get('email.failed_to_get_access_token') if self.translator else '获取访问令牌失败'}")
|
||||||
|
|
||||||
self.token = token_response.json()["token"]
|
self.token = token_response.json()["token"]
|
||||||
self.email = email
|
self.email = email
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}❌ 获取令牌时出错: {str(e)}{Style.RESET_ALL}")
|
||||||
|
raise
|
||||||
|
|
||||||
if self.translator:
|
if self.translator:
|
||||||
print(f"{Fore.GREEN}✅ {self.translator.get('email.create_success')}: {email}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}✅ {self.translator.get('email.create_success')}: {email}{Style.RESET_ALL}")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# 設置顏色主題
|
# set color theme
|
||||||
$Theme = @{
|
$Theme = @{
|
||||||
Primary = 'Cyan'
|
Primary = 'Cyan'
|
||||||
Success = 'Green'
|
Success = 'Green'
|
||||||
@@ -17,7 +17,7 @@ $Logo = @"
|
|||||||
╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝
|
╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝
|
||||||
"@
|
"@
|
||||||
|
|
||||||
# 美化輸出函數
|
# Beautiful Output Function
|
||||||
function Write-Styled {
|
function Write-Styled {
|
||||||
param (
|
param (
|
||||||
[string]$Message,
|
[string]$Message,
|
||||||
@@ -40,7 +40,7 @@ function Write-Styled {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# 獲取版本號函數
|
# Get version number function
|
||||||
function Get-LatestVersion {
|
function Get-LatestVersion {
|
||||||
try {
|
try {
|
||||||
$latestRelease = Invoke-RestMethod -Uri "https://api.github.com/repos/yeongpin/cursor-free-vip/releases/latest"
|
$latestRelease = Invoke-RestMethod -Uri "https://api.github.com/repos/yeongpin/cursor-free-vip/releases/latest"
|
||||||
@@ -54,28 +54,28 @@ function Get-LatestVersion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# 顯示 Logo
|
# Show Logo
|
||||||
Write-Host $Logo -ForegroundColor $Theme.Primary
|
Write-Host $Logo -ForegroundColor $Theme.Primary
|
||||||
$releaseInfo = Get-LatestVersion
|
$releaseInfo = Get-LatestVersion
|
||||||
$version = $releaseInfo.Version
|
$version = $releaseInfo.Version
|
||||||
Write-Host "Version $version" -ForegroundColor $Theme.Info
|
Write-Host "Version $version" -ForegroundColor $Theme.Info
|
||||||
Write-Host "Created by YeongPin`n" -ForegroundColor $Theme.Info
|
Write-Host "Created by YeongPin`n" -ForegroundColor $Theme.Info
|
||||||
|
|
||||||
# 設置 TLS 1.2
|
# Set TLS 1.2
|
||||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||||
|
|
||||||
# 主安裝函數
|
# Main installation function
|
||||||
function Install-CursorFreeVIP {
|
function Install-CursorFreeVIP {
|
||||||
Write-Styled "Start downloading Cursor Free VIP" -Color $Theme.Primary -Prefix "Download"
|
Write-Styled "Start downloading Cursor Free VIP" -Color $Theme.Primary -Prefix "Download"
|
||||||
|
|
||||||
try {
|
try {
|
||||||
# 獲取最新版本
|
# Get latest version
|
||||||
Write-Styled "Checking latest version..." -Color $Theme.Primary -Prefix "Update"
|
Write-Styled "Checking latest version..." -Color $Theme.Primary -Prefix "Update"
|
||||||
$releaseInfo = Get-LatestVersion
|
$releaseInfo = Get-LatestVersion
|
||||||
$version = $releaseInfo.Version
|
$version = $releaseInfo.Version
|
||||||
Write-Styled "Found latest version: $version" -Color $Theme.Success -Prefix "Version"
|
Write-Styled "Found latest version: $version" -Color $Theme.Success -Prefix "Version"
|
||||||
|
|
||||||
# 查找對應的資源
|
# Find corresponding resources
|
||||||
$asset = $releaseInfo.Assets | Where-Object { $_.name -eq "CursorFreeVIP_${version}_windows.exe" }
|
$asset = $releaseInfo.Assets | Where-Object { $_.name -eq "CursorFreeVIP_${version}_windows.exe" }
|
||||||
if (!$asset) {
|
if (!$asset) {
|
||||||
Write-Styled "File not found: CursorFreeVIP_${version}_windows.exe" -Color $Theme.Error -Prefix "Error"
|
Write-Styled "File not found: CursorFreeVIP_${version}_windows.exe" -Color $Theme.Error -Prefix "Error"
|
||||||
@@ -86,22 +86,114 @@ function Install-CursorFreeVIP {
|
|||||||
throw "Cannot find target file"
|
throw "Cannot find target file"
|
||||||
}
|
}
|
||||||
|
|
||||||
# 下載到Downloads文件夾
|
# Check if Downloads folder already exists for the corresponding version
|
||||||
$DownloadsPath = [Environment]::GetFolderPath("UserProfile") + "\Downloads"
|
$DownloadsPath = [Environment]::GetFolderPath("UserProfile") + "\Downloads"
|
||||||
$downloadPath = Join-Path $DownloadsPath "CursorFreeVIP.exe"
|
$downloadPath = Join-Path $DownloadsPath "CursorFreeVIP_${version}_windows.exe"
|
||||||
|
|
||||||
Write-Styled "Downloading to Downloads folder..." -Color $Theme.Primary -Prefix "Download"
|
if (Test-Path $downloadPath) {
|
||||||
|
Write-Styled "Found existing installation file" -Color $Theme.Success -Prefix "Found"
|
||||||
|
Write-Styled "Location: $downloadPath" -Color $Theme.Info -Prefix "Location"
|
||||||
|
|
||||||
|
# Check if running with administrator privileges
|
||||||
|
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||||
|
|
||||||
|
if (-not $isAdmin) {
|
||||||
|
Write-Styled "Requesting administrator privileges..." -Color $Theme.Warning -Prefix "Admin"
|
||||||
|
|
||||||
|
# Create new process with administrator privileges
|
||||||
|
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
|
$startInfo.FileName = $downloadPath
|
||||||
|
$startInfo.UseShellExecute = $true
|
||||||
|
$startInfo.Verb = "runas"
|
||||||
|
|
||||||
|
try {
|
||||||
|
[System.Diagnostics.Process]::Start($startInfo)
|
||||||
|
Write-Styled "Program started with admin privileges" -Color $Theme.Success -Prefix "Launch"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Styled "Failed to start with admin privileges. Starting normally..." -Color $Theme.Warning -Prefix "Warning"
|
||||||
|
Start-Process $downloadPath
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# If already running with administrator privileges, start directly
|
||||||
|
Start-Process $downloadPath
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Styled "No existing installation file found, starting download..." -Color $Theme.Primary -Prefix "Download"
|
||||||
|
|
||||||
|
# Create WebClient and add progress event
|
||||||
$webClient = New-Object System.Net.WebClient
|
$webClient = New-Object System.Net.WebClient
|
||||||
$webClient.Headers.Add("User-Agent", "PowerShell Script")
|
$webClient.Headers.Add("User-Agent", "PowerShell Script")
|
||||||
$webClient.DownloadFile($asset.browser_download_url, $downloadPath)
|
|
||||||
|
|
||||||
|
# Define progress variables
|
||||||
|
$Global:downloadedBytes = 0
|
||||||
|
$Global:totalBytes = 0
|
||||||
|
$Global:lastProgress = 0
|
||||||
|
$Global:lastBytes = 0
|
||||||
|
$Global:lastTime = Get-Date
|
||||||
|
|
||||||
|
# Download progress event
|
||||||
|
$eventId = [guid]::NewGuid()
|
||||||
|
Register-ObjectEvent -InputObject $webClient -EventName DownloadProgressChanged -Action {
|
||||||
|
$Global:downloadedBytes = $EventArgs.BytesReceived
|
||||||
|
$Global:totalBytes = $EventArgs.TotalBytesToReceive
|
||||||
|
$progress = [math]::Round(($Global:downloadedBytes / $Global:totalBytes) * 100, 1)
|
||||||
|
|
||||||
|
# Only update display when progress changes by more than 1%
|
||||||
|
if ($progress -gt $Global:lastProgress + 1) {
|
||||||
|
$Global:lastProgress = $progress
|
||||||
|
$downloadedMB = [math]::Round($Global:downloadedBytes / 1MB, 2)
|
||||||
|
$totalMB = [math]::Round($Global:totalBytes / 1MB, 2)
|
||||||
|
|
||||||
|
# Calculate download speed
|
||||||
|
$currentTime = Get-Date
|
||||||
|
$timeSpan = ($currentTime - $Global:lastTime).TotalSeconds
|
||||||
|
if ($timeSpan -gt 0) {
|
||||||
|
$bytesChange = $Global:downloadedBytes - $Global:lastBytes
|
||||||
|
$speed = $bytesChange / $timeSpan
|
||||||
|
|
||||||
|
# Choose appropriate unit based on speed
|
||||||
|
$speedDisplay = if ($speed -gt 1MB) {
|
||||||
|
"$([math]::Round($speed / 1MB, 2)) MB/s"
|
||||||
|
} elseif ($speed -gt 1KB) {
|
||||||
|
"$([math]::Round($speed / 1KB, 2)) KB/s"
|
||||||
|
} else {
|
||||||
|
"$([math]::Round($speed, 2)) B/s"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`rDownloading: $downloadedMB MB / $totalMB MB ($progress%) - $speedDisplay" -NoNewline -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# Update last data
|
||||||
|
$Global:lastBytes = $Global:downloadedBytes
|
||||||
|
$Global:lastTime = $currentTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} | Out-Null
|
||||||
|
|
||||||
|
# Download completed event
|
||||||
|
Register-ObjectEvent -InputObject $webClient -EventName DownloadFileCompleted -Action {
|
||||||
|
Write-Host "`r" -NoNewline
|
||||||
Write-Styled "Download completed!" -Color $Theme.Success -Prefix "Complete"
|
Write-Styled "Download completed!" -Color $Theme.Success -Prefix "Complete"
|
||||||
|
Unregister-Event -SourceIdentifier $eventId
|
||||||
|
} | Out-Null
|
||||||
|
|
||||||
|
# Start download
|
||||||
|
$webClient.DownloadFileAsync([Uri]$asset.browser_download_url, $downloadPath)
|
||||||
|
|
||||||
|
# Wait for download to complete
|
||||||
|
while ($webClient.IsBusy) {
|
||||||
|
Start-Sleep -Milliseconds 100
|
||||||
|
}
|
||||||
|
|
||||||
Write-Styled "File location: $downloadPath" -Color $Theme.Info -Prefix "Location"
|
Write-Styled "File location: $downloadPath" -Color $Theme.Info -Prefix "Location"
|
||||||
Write-Styled "Starting program..." -Color $Theme.Primary -Prefix "Launch"
|
Write-Styled "Starting program..." -Color $Theme.Primary -Prefix "Launch"
|
||||||
|
|
||||||
# 運行程序
|
# Run program
|
||||||
Start-Process $downloadPath
|
Start-Process $downloadPath
|
||||||
|
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
Write-Styled $_.Exception.Message -Color $Theme.Error -Prefix "Error"
|
Write-Styled $_.Exception.Message -Color $Theme.Error -Prefix "Error"
|
||||||
@@ -109,7 +201,7 @@ function Install-CursorFreeVIP {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# 執行安裝
|
# Execute installation
|
||||||
try {
|
try {
|
||||||
Install-CursorFreeVIP
|
Install-CursorFreeVIP
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# 顏色定義
|
# Color definitions
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
@@ -22,7 +22,7 @@ EOF
|
|||||||
echo -e "${NC}"
|
echo -e "${NC}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# 获取下载文件夹路径
|
# Get download folder path
|
||||||
get_downloads_dir() {
|
get_downloads_dir() {
|
||||||
if [[ "$(uname)" == "Darwin" ]]; then
|
if [[ "$(uname)" == "Darwin" ]]; then
|
||||||
echo "$HOME/Downloads"
|
echo "$HOME/Downloads"
|
||||||
@@ -36,68 +36,95 @@ get_downloads_dir() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# 獲取最新版本
|
# Get latest version
|
||||||
get_latest_version() {
|
get_latest_version() {
|
||||||
echo -e "${CYAN}ℹ️ 正在檢查最新版本...${NC}"
|
echo -e "${CYAN}ℹ️ Checking latest version...${NC}"
|
||||||
local latest_release
|
local latest_release
|
||||||
latest_release=$(curl -s https://api.github.com/repos/yeongpin/cursor-free-vip/releases/latest)
|
latest_release=$(curl -s https://api.github.com/repos/yeongpin/cursor-free-vip/releases/latest)
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo -e "${RED}❌ 無法獲取最新版本信息${NC}"
|
echo -e "${RED}❌ Cannot get latest version information${NC}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
VERSION=$(echo "$latest_release" | grep -o '"tag_name": ".*"' | cut -d'"' -f4 | tr -d 'v')
|
VERSION=$(echo "$latest_release" | grep -o '"tag_name": ".*"' | cut -d'"' -f4 | tr -d 'v')
|
||||||
echo -e "${GREEN}✅ 找到最新版本: ${VERSION}${NC}"
|
echo -e "${GREEN}✅ Found latest version: ${VERSION}${NC}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# 檢測系統類型和架構
|
# Detect system type and architecture
|
||||||
detect_os() {
|
detect_os() {
|
||||||
if [[ "$(uname)" == "Darwin" ]]; then
|
if [[ "$(uname)" == "Darwin" ]]; then
|
||||||
# 检测 macOS 架构
|
# Detect macOS architecture
|
||||||
ARCH=$(uname -m)
|
ARCH=$(uname -m)
|
||||||
if [[ "$ARCH" == "arm64" ]]; then
|
if [[ "$ARCH" == "arm64" ]]; then
|
||||||
OS="mac_arm64"
|
OS="mac_arm64"
|
||||||
echo -e "${CYAN}ℹ️ 检测到 macOS ARM64 架构${NC}"
|
echo -e "${CYAN}ℹ️ Detected macOS ARM64 architecture${NC}"
|
||||||
else
|
else
|
||||||
OS="mac_intel"
|
OS="mac_intel"
|
||||||
echo -e "${CYAN}ℹ️ 检测到 macOS Intel 架构${NC}"
|
echo -e "${CYAN}ℹ️ Detected macOS Intel architecture${NC}"
|
||||||
fi
|
fi
|
||||||
elif [[ "$(uname)" == "Linux" ]]; then
|
elif [[ "$(uname)" == "Linux" ]]; then
|
||||||
OS="linux"
|
OS="linux"
|
||||||
echo -e "${CYAN}ℹ️ 检测到 Linux 系统${NC}"
|
echo -e "${CYAN}ℹ️ Detected Linux system${NC}"
|
||||||
else
|
else
|
||||||
# 假设是 Windows
|
# Assume Windows
|
||||||
OS="windows"
|
OS="windows"
|
||||||
echo -e "${CYAN}ℹ️ 检测到 Windows 系统${NC}"
|
echo -e "${CYAN}ℹ️ Detected Windows system${NC}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# 下載並安裝
|
# Install and download
|
||||||
install_cursor_free_vip() {
|
install_cursor_free_vip() {
|
||||||
local downloads_dir=$(get_downloads_dir)
|
local downloads_dir=$(get_downloads_dir)
|
||||||
local binary_name="CursorFreeVIP_${VERSION}_${OS}"
|
local binary_name="CursorFreeVIP_${VERSION}_${OS}"
|
||||||
local binary_path="${downloads_dir}/cursor-free-vip"
|
local binary_path="${downloads_dir}/${binary_name}"
|
||||||
local download_url="https://github.com/yeongpin/cursor-free-vip/releases/download/v${VERSION}/${binary_name}"
|
local download_url="https://github.com/yeongpin/cursor-free-vip/releases/download/v${VERSION}/${binary_name}"
|
||||||
|
|
||||||
echo -e "${CYAN}ℹ️ 正在下載到 ${downloads_dir}...${NC}"
|
# Check if file already exists
|
||||||
echo -e "${CYAN}ℹ️ 下載鏈接: ${download_url}${NC}"
|
if [ -f "${binary_path}" ]; then
|
||||||
|
echo -e "${GREEN}✅ Found existing installation file${NC}"
|
||||||
|
echo -e "${CYAN}ℹ️ Location: ${binary_path}${NC}"
|
||||||
|
|
||||||
# 先检查文件是否存在
|
# Check if running as root
|
||||||
if curl --output /dev/null --silent --head --fail "$download_url"; then
|
if [ "$EUID" -ne 0 ]; then
|
||||||
echo -e "${GREEN}✅ 文件存在,开始下载...${NC}"
|
echo -e "${YELLOW}⚠️ Requesting administrator privileges...${NC}"
|
||||||
|
if command -v sudo >/dev/null 2>&1; then
|
||||||
|
echo -e "${CYAN}ℹ️ Starting program with sudo...${NC}"
|
||||||
|
sudo chmod +x "${binary_path}"
|
||||||
|
sudo "${binary_path}"
|
||||||
else
|
else
|
||||||
echo -e "${RED}❌ 下载链接不存在: ${download_url}${NC}"
|
echo -e "${YELLOW}⚠️ sudo not found, trying to run normally...${NC}"
|
||||||
echo -e "${YELLOW}⚠️ 尝试不带架构的版本...${NC}"
|
chmod +x "${binary_path}"
|
||||||
|
"${binary_path}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Already running as root
|
||||||
|
echo -e "${CYAN}ℹ️ Already running as root, starting program...${NC}"
|
||||||
|
chmod +x "${binary_path}"
|
||||||
|
"${binary_path}"
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# 尝试不带架构的版本
|
echo -e "${CYAN}ℹ️ No existing installation file found, starting download...${NC}"
|
||||||
|
echo -e "${CYAN}ℹ️ Downloading to ${downloads_dir}...${NC}"
|
||||||
|
echo -e "${CYAN}ℹ️ Download link: ${download_url}${NC}"
|
||||||
|
|
||||||
|
# Check if file exists
|
||||||
|
if curl --output /dev/null --silent --head --fail "$download_url"; then
|
||||||
|
echo -e "${GREEN}✅ File exists, starting download...${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${RED}❌ Download link does not exist: ${download_url}${NC}"
|
||||||
|
echo -e "${YELLOW}⚠️ Trying without architecture...${NC}"
|
||||||
|
|
||||||
|
# Try without architecture
|
||||||
if [[ "$OS" == "mac_arm64" || "$OS" == "mac_intel" ]]; then
|
if [[ "$OS" == "mac_arm64" || "$OS" == "mac_intel" ]]; then
|
||||||
OS="mac"
|
OS="mac"
|
||||||
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}"
|
||||||
echo -e "${CYAN}ℹ️ 新下载链接: ${download_url}${NC}"
|
echo -e "${CYAN}ℹ️ New download link: ${download_url}${NC}"
|
||||||
|
|
||||||
if ! curl --output /dev/null --silent --head --fail "$download_url"; then
|
if ! curl --output /dev/null --silent --head --fail "$download_url"; then
|
||||||
echo -e "${RED}❌ 新下载链接也不存在${NC}"
|
echo -e "${RED}❌ New download link does not exist${NC}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
@@ -105,43 +132,43 @@ install_cursor_free_vip() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 下载文件
|
# Download file
|
||||||
if ! curl -L -o "${binary_path}" "$download_url"; then
|
if ! curl -L -o "${binary_path}" "$download_url"; then
|
||||||
echo -e "${RED}❌ 下載失敗${NC}"
|
echo -e "${RED}❌ Download failed${NC}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 检查下载的文件大小
|
# Check downloaded file size
|
||||||
local file_size=$(stat -f%z "${binary_path}" 2>/dev/null || stat -c%s "${binary_path}" 2>/dev/null)
|
local file_size=$(stat -f%z "${binary_path}" 2>/dev/null || stat -c%s "${binary_path}" 2>/dev/null)
|
||||||
echo -e "${CYAN}ℹ️ 下載的文件大小: ${file_size} 字節${NC}"
|
echo -e "${CYAN}ℹ️ Downloaded file size: ${file_size} bytes${NC}"
|
||||||
|
|
||||||
# 如果文件太小,可能是错误信息
|
# If file is too small, it might be an error message
|
||||||
if [ "$file_size" -lt 1000 ]; then
|
if [ "$file_size" -lt 1000 ]; then
|
||||||
echo -e "${YELLOW}⚠️ 警告: 下載的文件太小,可能不是有效的可執行文件${NC}"
|
echo -e "${YELLOW}⚠️ Warning: Downloaded file is too small, possibly not a valid executable file${NC}"
|
||||||
echo -e "${YELLOW}⚠️ 文件內容:${NC}"
|
echo -e "${YELLOW}⚠️ File content:${NC}"
|
||||||
cat "${binary_path}"
|
cat "${binary_path}"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${RED}❌ 下載失敗,請檢查版本號和操作系統是否正確${NC}"
|
echo -e "${RED}❌ Download failed, please check version and operating system${NC}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "${CYAN}ℹ️ 正在設置執行權限...${NC}"
|
echo -e "${CYAN}ℹ️ Setting executable permissions...${NC}"
|
||||||
chmod +x "${binary_path}"
|
chmod +x "${binary_path}"
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo -e "${GREEN}✅ 安裝完成!${NC}"
|
echo -e "${GREEN}✅ Installation completed!${NC}"
|
||||||
echo -e "${CYAN}ℹ️ 程序已下載到: ${binary_path}${NC}"
|
echo -e "${CYAN}ℹ️ Program downloaded to: ${binary_path}${NC}"
|
||||||
echo -e "${CYAN}ℹ️ 正在啟動程序...${NC}"
|
echo -e "${CYAN}ℹ️ Starting program...${NC}"
|
||||||
|
|
||||||
# 直接运行程序
|
# Run program directly
|
||||||
"${binary_path}"
|
"${binary_path}"
|
||||||
else
|
else
|
||||||
echo -e "${RED}❌ 安裝失敗${NC}"
|
echo -e "${RED}❌ Installation failed${NC}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# 主程序
|
# Main program
|
||||||
main() {
|
main() {
|
||||||
print_logo
|
print_logo
|
||||||
get_latest_version
|
get_latest_version
|
||||||
@@ -149,5 +176,5 @@ main() {
|
|||||||
install_cursor_free_vip
|
install_cursor_free_vip
|
||||||
}
|
}
|
||||||
|
|
||||||
# 運行主程序
|
# Run main program
|
||||||
main
|
main
|
||||||
Reference in New Issue
Block a user