Compare commits

..

24 Commits

Author SHA1 Message Date
yeongpin
4122701468 test2 2025-02-08 23:07:23 +08:00
yeongpin
1ee9813155 test1 2025-02-08 23:05:50 +08:00
yeongpin
a9e4b3a5c6 test 2025-02-08 23:02:22 +08:00
yeongpin
a83851d441 update new build.yml 2025-02-08 22:54:02 +08:00
yeongpin
1e290d0417 build.yml update 2025-02-08 22:50:05 +08:00
yeongpin
53ab15604e update build 2025-02-08 22:45:32 +08:00
yeongpin
638916e5ef update github 2025-02-08 22:38:11 +08:00
yeongpin
9500ce1249 update new build 2025-02-08 22:22:19 +08:00
yeongpin
721c13cb2f update build 2025-02-08 22:16:02 +08:00
yeongpin
a04eed2c6b update build.yml 2025-02-08 22:12:17 +08:00
yeongpin
8107bede63 update remake 2025-02-08 22:10:00 +08:00
yeongpin
4166bc5135 update reissue 2025-02-08 22:04:14 +08:00
yeongpin
69994d2486 update v4 2025-02-08 22:02:01 +08:00
yeongpin
ffcb8ec140 update 2025-02-08 22:00:19 +08:00
yeongpin
b61b61c607 add workflow 2025-02-08 21:57:44 +08:00
yeongpin
7326d0eeb0 newest reset machine 2025-02-08 21:52:16 +08:00
yeongpin
371f00645d update readme 2025-02-05 19:33:42 +08:00
yeongpin
a873291481 update env 2025-02-05 19:22:01 +08:00
yeongpin
7710ea4bb3 Update support 0.45 2025-02-05 19:21:34 +08:00
yeongpin
13483eed77 update auth message & reset message 2025-01-17 10:12:18 +08:00
yeongpin
eb69f933af Update & Fix reset machine problem 2025-01-15 17:14:05 +08:00
yeongpin
54cd8cf323 Update 107 2025-01-15 13:54:38 +08:00
yeongpin
4e0289c86c Update New107 images 2025-01-15 13:46:54 +08:00
yeongpin
af4a1c4065 Update Readme 2025-01-15 13:44:22 +08:00
16 changed files with 771 additions and 90 deletions

4
.env
View File

@@ -1,2 +1,2 @@
version=1.0.7 version=1.0.9
VERSION=1.0.7 VERSION=1.0.9

201
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,201 @@
name: Build Executables
on:
workflow_dispatch:
inputs:
version:
description: 'Version number (e.g. 1.0.9)'
required: true
default: '1.0.9-dev'
permissions:
contents: write
actions: write
packages: write
jobs:
create-tag:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0 # 获取所有标签
- name: Delete existing tag if exists
run: |
if git ls-remote --tags origin | grep -q "refs/tags/v${{ github.event.inputs.version }}"; then
git push origin --delete "v${{ github.event.inputs.version }}" || true
git tag -d "v${{ github.event.inputs.version }}" || true
fi
- name: Create Tag
run: |
git tag "v${{ github.event.inputs.version }}"
git push origin "v${{ github.event.inputs.version }}"
build-windows:
needs: create-tag
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Set version
shell: bash
run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pyinstaller
pip install -r requirements.txt
- name: Build EXE
run: |
pyinstaller build.spec
- name: Upload Windows artifact
uses: actions/upload-artifact@v4
with:
name: CursorFreeVIP_${{ env.VERSION }}_windows.exe
path: dist/*
build-macos-arm64:
needs: create-tag
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Set version
shell: bash
run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pyinstaller
pip install -r requirements.txt
- name: Build MacOS ARM executable
run: |
pyinstaller build.spec
- name: Upload MacOS ARM artifact
uses: actions/upload-artifact@v4
with:
name: CursorFreeVIP_${{ env.VERSION }}_mac_arm64
path: dist/*
build-linux:
needs: create-tag
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Set version
shell: bash
run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pyinstaller
pip install -r requirements.txt
- name: Build Linux executable
run: |
pyinstaller build.spec
- name: Upload Linux artifact
uses: actions/upload-artifact@v4
with:
name: CursorFreeVIP_${{ env.VERSION }}_linux
path: dist/*
build-macos-intel:
needs: create-tag
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Set version
shell: bash
run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
- name: Install dependencies
run: |
arch -x86_64 pip3 install --upgrade pip
arch -x86_64 pip3 install pyinstaller
arch -x86_64 pip3 install -r requirements.txt
- name: Build MacOS Intel executable
env:
TARGET_ARCH: 'x86_64'
run: |
arch -x86_64 python3 -m PyInstaller build.spec
- name: Upload MacOS Intel artifact
uses: actions/upload-artifact@v4
with:
name: CursorFreeVIP_${{ env.VERSION }}_mac_intel
path: dist/*
create-release:
needs: [build-windows, build-macos-arm64, build-linux, build-macos-intel]
runs-on: ubuntu-22.04
steps:
- name: Get version
shell: bash
run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: List and prepare files
run: |
cd artifacts
ls -la
echo "Current files in artifacts:"
find . -type f
- name: Create Release
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ env.VERSION }}
files: |
artifacts/CursorFreeVIP_${{ env.VERSION }}_windows.exe/CursorFreeVIP.exe
artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_arm64/CursorFreeVIP
artifacts/CursorFreeVIP_${{ env.VERSION }}_linux/CursorFreeVIP
artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_intel/CursorFreeVIP
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -11,13 +11,14 @@
[![Stars](https://img.shields.io/github/stars/yeongpin/cursor-free-vip?style=flat-square&logo=github)](https://github.com/yeongpin/cursor-free-vip/stargazers) [![Stars](https://img.shields.io/github/stars/yeongpin/cursor-free-vip?style=flat-square&logo=github)](https://github.com/yeongpin/cursor-free-vip/stargazers)
</p> </p>
<h4>Support Latest 0.45.11 Version | 支持最新0.45.11版本</h4>
This is a tool to automatically register (except for Google verification code), support Windows and macOS systems, complete Auth verification, and reset Cursor's configuration. This is a tool to automatically register (except for Google verification code), support Windows and macOS systems, complete Auth verification, and reset Cursor's configuration.
這是一個自動化工具自動註冊除了Google驗證碼),支持 Windows 和 macOS 系統完成Auth驗證重置Cursor的配置。 這是一個自動化工具自動註冊除了Google驗證碼),支持 Windows 和 macOS 系統完成Auth驗證重置Cursor的配置。
<p align="center"> <p align="center">
<img src="./images/pro_2025-01-14_14-40-37.png" alt="new" width="400"/><br> <img src="./images/new107_2025-01-15_13-53-56.png" alt="new" width="400"/><br>
</p> </p>
<br> <br>
@@ -37,6 +38,34 @@ This is a tool to automatically register (except for Google verification code),
## 🔄 更新日志 ## 🔄 更新日志
<details open> <details open>
<summary>v1.0.9</summary>
<p align="center">
<img src="./images/pass_2025-02-08_21-48-36.png" alt="free" width="400"/><br>
</p>
1. Fixed New 0.45.x Version Reset Machine | 修復新0.45版本重置機器
2. Fix Locale Language | 修復多語言
3. Add Support Crypto Machine Regedit | 增加支持加密機器註冊
4. Add Remake main.js | 重做main.js
</details>
<details>
<summary>Other Version Change Log</summary>
<details>
<summary>v1.0.8</summary>
1. Fix New 0.45 Version Reset Machine | 修復新0.45版本重置機器
2. Fix Locale Language | 修復多語言
3. Add Support Crypto Machine Regedit | 增加支持加密機器註冊
</details>
<details>
<summary>v1.0.7 - HotFix</summary>
1. Fix Reset Machine | 修復重置機器
2. Fix Locale Language | 修復多語言
</details>
<details>
<summary>v1.0.7</summary> <summary>v1.0.7</summary>
1. Add Locale Language Support | 增加多語言支持 1. Add Locale Language Support | 增加多語言支持
@@ -130,6 +159,7 @@ This is a tool to automatically register (except for Google verification code),
<img src="./images/pro_2025-01-11_16-24-03.png" alt="Cursor Pro Logo" width="400"/><br> <img src="./images/pro_2025-01-11_16-24-03.png" alt="Cursor Pro Logo" width="400"/><br>
</p> </p>
</details> </details>
</details>
## ✨ Features | 功能特點 ## ✨ Features | 功能特點

View File

@@ -2,6 +2,7 @@ from DrissionPage import ChromiumOptions, ChromiumPage
import sys import sys
import os import os
import logging import logging
import random
class BrowserManager: class BrowserManager:
@@ -36,17 +37,58 @@ class BrowserManager:
except FileNotFoundError as e: except FileNotFoundError as e:
logging.warning(f"警告: {e}") logging.warning(f"警告: {e}")
# 设置更真实的用户代理
co.set_user_agent( co.set_user_agent(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36" "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.set_pref("credentials_enable_service", False)
co.set_pref("profile.password_manager_enabled", False)
# 禁用自动化标志
co.set_pref("useAutomationExtension", False)
co.set_pref("excludeSwitches", ["enable-automation"])
# WebGL 和 GPU 设置
co.set_pref("webgl.disabled", False)
co.set_pref("webgl.enable_webgl2", True)
# 设置语言和地区
co.set_pref("intl.accept_languages", "en-US,en")
# 基本命令行参数
co.set_argument("--disable-blink-features=AutomationControlled")
co.set_argument("--hide-crash-restore-bubble") co.set_argument("--hide-crash-restore-bubble")
co.set_argument("--no-first-run")
co.set_argument("--no-default-browser-check")
co.set_argument("--disable-popup-blocking")
# 性能和稳定性参数
co.set_argument("--disable-dev-shm-usage")
co.set_argument("--disable-gpu")
co.set_argument("--no-sandbox")
co.set_argument("--ignore-certificate-errors")
# WebGL 相关参数
co.set_argument("--use-gl=swiftshader")
co.set_argument("--enable-webgl")
# 随机端口
co.auto_port() co.auto_port()
# Mac 系统特殊处理 # 系统特定设置
if sys.platform == "darwin": if sys.platform == "darwin": # macOS
co.set_argument("--no-sandbox")
co.set_argument("--disable-gpu") 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 return co

View File

@@ -31,7 +31,8 @@ a = Analysis(
('reset_machine_manual.py', '.'), ('reset_machine_manual.py', '.'),
('cursor_register.py', '.'), ('cursor_register.py', '.'),
('browser.py', '.'), ('browser.py', '.'),
('control.py', '.') ('control.py', '.'),
('.env', '.')
], ],
hiddenimports=[ hiddenimports=[
'cursor_auth', 'cursor_auth',

View File

@@ -77,7 +77,7 @@ class BrowserControl:
return False return False
def select_email_domain(self, domain_index=None): def select_email_domain(self, domain_index=None):
"""选择邮箱域名如果不指定index则随机选择""" """选择邮箱域名如果不指定index则随机选择。避免选择fr.nf域名"""
try: try:
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.select_email_domain')}...{Style.RESET_ALL}") print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.select_email_domain')}...{Style.RESET_ALL}")
# 找到下拉框 # 找到下拉框
@@ -95,21 +95,38 @@ class BrowserControl:
all_options.extend(other_options) all_options.extend(other_options)
if all_options: if all_options:
# 如果没有指定索引,随机选择一个 max_attempts = 5 # 最大尝试次数
if domain_index is None: attempt = 0
domain_index = random.randint(0, len(all_options) - 1)
if domain_index < len(all_options): while attempt < max_attempts:
# 获取选中选项的文本 # 如果没有指定索引,随机选择一个
selected_domain = all_options[domain_index].text if domain_index is None:
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.select_email_domain')}: {selected_domain}{Style.RESET_ALL}") domain_index = random.randint(0, len(all_options) - 1)
# 点击选择 if domain_index < len(all_options):
all_options[domain_index].click() # 获取选中选项的文本
time.sleep(1) selected_domain = all_options[domain_index].text
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.select_email_domain_success')}{Style.RESET_ALL}")
return True # 检查是否为fr.nf域名
if "fr.nf" in selected_domain.lower():
print(f"{Fore.YELLOW}{EMOJI['INFO']} 检测到fr.nf域名重新选择...{Style.RESET_ALL}")
domain_index = None # 重置索引以便重新随机选择
attempt += 1
continue
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.select_email_domain')}: {selected_domain}{Style.RESET_ALL}")
# 点击选择
all_options[domain_index].click()
time.sleep(1)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.select_email_domain_success')}{Style.RESET_ALL}")
return True
attempt += 1
print(f"{Fore.RED}{EMOJI['ERROR']} 无法找到合适的非fr.nf域名{Style.RESET_ALL}")
return False
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.no_available_domain_options', count=len(all_options))}{Style.RESET_ALL}") print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.no_available_domain_options', count=len(all_options))}{Style.RESET_ALL}")
return False return False
else: else:

View File

@@ -56,7 +56,7 @@ class CursorAuth:
# 重新连接数据库 # 重新连接数据库
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()
# 增加超时和其他优化设置 # 增加超时和其他优化设置
@@ -90,7 +90,7 @@ class CursorAuth:
UPDATE ItemTable SET value = ? UPDATE ItemTable SET value = ?
WHERE key = ? WHERE key = ?
""", (value, key)) """, (value, key))
print(f"{EMOJI['INFO']} {Fore.CYAN}Updating {key.split('/')[-1]}...{Style.RESET_ALL}") print(f"{EMOJI['INFO']} {Fore.CYAN} {self.translator.get('auth.updating_pair')} {key.split('/')[-1]}...{Style.RESET_ALL}")
cursor.execute("COMMIT") cursor.execute("COMMIT")
print(f"{EMOJI['SUCCESS']} {Fore.GREEN}{self.translator.get('auth.database_updated_successfully')}{Style.RESET_ALL}") print(f"{EMOJI['SUCCESS']} {Fore.GREEN}{self.translator.get('auth.database_updated_successfully')}{Style.RESET_ALL}")
@@ -101,14 +101,14 @@ class CursorAuth:
raise e raise e
except sqlite3.Error as e: except sqlite3.Error as e:
print(f"\n{EMOJI['ERROR']} {Fore.RED}{self.translator.get('auth.database_error', error=str(e))}{Style.RESET_ALL}") print(f"\n{EMOJI['ERROR']} {Fore.RED} {self.translator.get('auth.database_error', error=str(e))}{Style.RESET_ALL}")
return False return False
except Exception as e: except Exception as e:
print(f"\n{EMOJI['ERROR']} {Fore.RED}{self.translator.get('auth.an_error_occurred', error=str(e))}{Style.RESET_ALL}") print(f"\n{EMOJI['ERROR']} {Fore.RED} {self.translator.get('auth.an_error_occurred', error=str(e))}{Style.RESET_ALL}")
return False return False
finally: finally:
if conn: if conn:
conn.close() conn.close()
print(f"{EMOJI['DB']} {Fore.CYAN}{self.translator.get('auth.database_connection_closed')}{Style.RESET_ALL}") print(f"{EMOJI['DB']} {Fore.CYAN} {self.translator.get('auth.database_connection_closed')}{Style.RESET_ALL}")

View File

@@ -102,7 +102,7 @@ class CursorRegistration:
# 创建新的浏览器实例用于注册 # 创建新的浏览器实例用于注册
from browser import BrowserManager from browser import BrowserManager
signup_browser_manager = BrowserManager(noheader=True) signup_browser_manager = BrowserManager(noheader=False)
self.signup_tab = signup_browser_manager.init_browser() self.signup_tab = signup_browser_manager.init_browser()
# 访问注册页面 # 访问注册页面
@@ -144,10 +144,10 @@ class CursorRegistration:
# 获取验证码设置60秒超时 # 获取验证码设置60秒超时
verification_code = None verification_code = None
max_attempts = 10 # 增加到10次尝试 max_attempts = 20 # 增加到10次尝试
retry_interval = 5 # 每5秒重试一次 retry_interval = 10 # 每5秒重试一次
start_time = time.time() start_time = time.time()
timeout = 60 # 60秒超时 timeout = 160 # 60秒超时
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.start_getting_verification_code')}...{Style.RESET_ALL}") print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.start_getting_verification_code')}...{Style.RESET_ALL}")
@@ -246,56 +246,87 @@ class CursorRegistration:
def _handle_turnstile(self): def _handle_turnstile(self):
"""处理 Turnstile 验证""" """处理 Turnstile 验证"""
print(f"{Fore.YELLOW}{EMOJI['VERIFY']} {self.translator.get('register.handle_turnstile')}...{Style.RESET_ALL}") try:
print(f"{Fore.YELLOW}{EMOJI['VERIFY']} {self.translator.get('register.handle_turnstile')}...{Style.RESET_ALL}")
# 设置最大等待时间(秒)
max_wait_time = 10 # 增加等待时间 max_retries = 2
start_time = time.time() retry_interval = (1, 2)
retry_count = 0
while True:
try: while retry_count < max_retries:
# 检查是否超时 retry_count += 1
if time.time() - start_time > max_wait_time: print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('register.turnstile_attempt', attempt=retry_count)}...{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['WAIT']} {self.translator.get('register.no_turnstile')}...{Style.RESET_ALL}")
time.sleep(2)
break
try: try:
challengeCheck = ( # 尝试重置 turnstile
self.signup_tab.ele("@id=cf-turnstile", timeout=1) self.signup_tab.run_js("try { turnstile.reset() } catch(e) { }")
time.sleep(2)
# 定位验证框元素
challenge_check = (
self.signup_tab.ele("@id=cf-turnstile", timeout=2)
.child() .child()
.shadow_root.ele("tag:iframe") .shadow_root.ele("tag:iframe")
.ele("tag:body") .ele("tag:body")
.sr("tag:input") .sr("tag:input")
) )
if challengeCheck: if challenge_check:
challengeCheck.click() print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('register.turnstile_detected')}...{Style.RESET_ALL}")
time.sleep(3)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.turnstile_passed')}{Style.RESET_ALL}") # 随机延时后点击验证
time.sleep(random.uniform(1, 3))
challenge_check.click()
time.sleep(2) time.sleep(2)
break
except:
pass
try:
if (self.signup_tab.ele("@name=password", timeout=0.5) or
self.signup_tab.ele("@name=email", timeout=0.5) or
self.signup_tab.ele("@data-index=0", timeout=0.5)):
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.turnstile_passed')}{Style.RESET_ALL}")
time.sleep(2)
break
except:
pass
time.sleep(1)
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.error', error=str(e))}{Style.RESET_ALL}")
time.sleep(2)
break
time.sleep(2) # 检查验证结果
if self._check_verification_success():
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.turnstile_passed')}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('register.turnstile_attempt_failed', error=str(e))}{Style.RESET_ALL}")
# 检查是否已经验证成功
if self._check_verification_success():
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.turnstile_passed')}{Style.RESET_ALL}")
return True
# 随机延时后继续下一次尝试
time.sleep(random.uniform(*retry_interval))
# 超出最大重试次数
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.turnstile_max_retries', max=max_retries)}{Style.RESET_ALL}")
return False
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.turnstile_error', error=str(e))}{Style.RESET_ALL}")
return False
def _check_verification_success(self):
"""检查验证是否成功"""
try:
# 检查是否存在后续表单元素,这表示验证已通过
if (self.signup_tab.ele("@name=password", timeout=0.5) or
self.signup_tab.ele("@name=email", timeout=0.5) or
self.signup_tab.ele("@data-index=0", timeout=0.5) or
self.signup_tab.ele("Account Settings", timeout=0.5)):
return True
# 检查是否出现错误消息
error_messages = [
'xpath://div[contains(text(), "Can\'t verify the user is human")]',
'xpath://div[contains(text(), "Error: 600010")]',
'xpath://div[contains(text(), "Please try again")]'
]
for error_xpath in error_messages:
if self.signup_tab.ele(error_xpath):
return False
return False
except:
return False
def _get_account_info(self): def _get_account_info(self):
"""获取账户信息和 Token""" """获取账户信息和 Token"""

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

View File

@@ -45,10 +45,29 @@
"updating_pair": "Updating Key-Value Pair", "updating_pair": "Updating Key-Value Pair",
"sqlite_success": "SQLite Database Updated Successfully", "sqlite_success": "SQLite Database Updated Successfully",
"sqlite_error": "SQLite Database Update Failed: {error}", "sqlite_error": "SQLite Database Update Failed: {error}",
"press_enter": "Press Enter to Exit" "press_enter": "Press Enter to Exit",
"unsupported_os": "Unsupported OS: {os}",
"linux_path_not_found": "Linux Path Not Found",
"updating_system_ids": "Updating System IDs",
"system_ids_updated": "System IDs Updated Successfully",
"system_ids_update_failed": "System IDs Update Failed: {error}",
"windows_guid_updated": "Windows GUID Updated Successfully",
"windows_permission_denied": "Windows Permission Denied",
"windows_guid_update_failed": "Windows GUID Update Failed",
"macos_uuid_updated": "macOS UUID Updated Successfully",
"plutil_command_failed": "plutil Command Failed",
"start_patching": "Starting Patching getMachineId",
"macos_uuid_update_failed": "macOS UUID Update Failed",
"current_version": "Current Cursor Version: {version}",
"patch_completed": "Patching getMachineId Completed",
"patch_failed": "Patching getMachineId Failed: {error}",
"version_check_passed": "Cursor Version Check Passed",
"file_modified": "File Modified"
}, },
"register": { "register": {
"title": "Cursor Registration Tool", "title": "Cursor Registration Tool",
"start": "Starting Registration Process", "start": "Starting Registration Process",
"mailbox": "Successfully Entered Mailbox", "mailbox": "Successfully Entered Mailbox",
"register_start": "Start Register", "register_start": "Start Register",
@@ -107,7 +126,8 @@
"reset_machine_id": "Reset Machine ID", "reset_machine_id": "Reset Machine ID",
"database_connection_closed": "Database Connection Closed", "database_connection_closed": "Database Connection Closed",
"database_updated_successfully": "Database Updated Successfully", "database_updated_successfully": "Database Updated Successfully",
"connected_to_database": "Connected to Database" "connected_to_database": "Connected to Database",
"updating_pair": "Updating Key-Value Pair"
}, },
"control": { "control": {
"generate_email": "Generating New Email", "generate_email": "Generating New Email",
@@ -136,6 +156,8 @@
"get_cursor_session_token": "Get Cursor Session Token", "get_cursor_session_token": "Get Cursor Session Token",
"get_cursor_session_token_success": "Get Cursor Session Token Success", "get_cursor_session_token_success": "Get Cursor Session Token Success",
"get_cursor_session_token_failed": "Get Cursor Session Token Failed", "get_cursor_session_token_failed": "Get Cursor Session Token Failed",
"save_token_failed": "Save Token Failed" "save_token_failed": "Save Token Failed",
"database_updated_successfully": "Database Updated Successfully",
"database_connection_closed": "Database Connection Closed"
} }
} }

View File

@@ -26,6 +26,44 @@
"timeout": "以下进程未能在规定时间内关闭: {pids}", "timeout": "以下进程未能在规定时间内关闭: {pids}",
"error": "关闭 Cursor 进程时发生错误: {error}" "error": "关闭 Cursor 进程时发生错误: {error}"
}, },
"reset": {
"title": "Cursor 机器标识重置工具",
"checking": "检查配置文件",
"not_found": "配置文件未找到",
"no_permission": "无法读取或写入配置文件,请检查文件权限",
"reading": "读取当前配置",
"creating_backup": "创建配置备份",
"backup_exists": "备份文件已存在,跳过备份步骤",
"generating": "生成新机器标识",
"saving_json": "保存新配置到JSON",
"success": "机器标识重置成功",
"new_id": "新机器标识",
"permission_error": "权限错误: {error}",
"run_as_admin": "请尝试以管理员身份运行此程序",
"process_error": "重置进程错误: {error}",
"updating_sqlite": "更新SQLite数据库",
"updating_pair": "更新键值对",
"sqlite_success": "SQLite数据库更新成功",
"sqlite_error": "SQLite数据库更新失败: {error}",
"press_enter": "按回车键退出",
"updating_system_ids": "更新系统ID",
"system_ids_updated": "系统ID更新成功",
"system_ids_update_failed": "系统ID更新失败: {error}",
"unsupported_os": "不支持的操作系统: {os}",
"linux_path_not_found": "Linux路径未找到",
"windows_guid_updated": "Windows GUID更新成功",
"windows_permission_denied": "Windows权限拒绝",
"windows_guid_update_failed": "Windows GUID更新失败",
"macos_uuid_updated": "macOS UUID更新成功",
"plutil_command_failed": "plutil命令失败",
"macos_uuid_update_failed": "macOS UUID更新失败",
"start_patching": "开始修补getMachineId",
"current_version": "当前Cursor版本: {version}",
"patch_completed": "getMachineId修补完成",
"patch_failed": "getMachineId修补失败: {error}",
"version_check_passed": "Cursor版本检查通过",
"file_modified": "文件已修改"
},
"register": { "register": {
"title": "Cursor 注册工具", "title": "Cursor 注册工具",
"start": "开始注册流程", "start": "开始注册流程",
@@ -68,7 +106,8 @@
"account_info_saved": "账户信息已保存", "account_info_saved": "账户信息已保存",
"save_account_info_failed": "保存账户信息失败", "save_account_info_failed": "保存账户信息失败",
"get_email_address": "获取邮箱地址", "get_email_address": "获取邮箱地址",
"register_process_error": "注册流程错误: {error}" "register_process_error": "注册流程错误: {error}",
"update_cursor_auth_info": "更新Cursor认证信息"
}, },
"auth": { "auth": {
"title": "Cursor 认证管理器", "title": "Cursor 认证管理器",
@@ -81,7 +120,11 @@
"auth_update_failed": "认证信息更新失败: {error}", "auth_update_failed": "认证信息更新失败: {error}",
"auth_file_created": "认证文件已创建", "auth_file_created": "认证文件已创建",
"auth_file_create_failed": "认证文件创建失败: {error}", "auth_file_create_failed": "认证文件创建失败: {error}",
"press_enter": "按回车键退出" "press_enter": "按回车键退出",
"connected_to_database": "已连接到数据库",
"database_updated_successfully": "数据库更新成功",
"database_connection_closed": "数据库连接已关闭",
"updating_pair": "更新键值对"
}, },
"control": { "control": {
"generate_email": "生成新邮箱", "generate_email": "生成新邮箱",

View File

@@ -26,6 +26,48 @@
"timeout": "以下進程未能在規定時間內關閉: {pids}", "timeout": "以下進程未能在規定時間內關閉: {pids}",
"error": "關閉 Cursor 進程時發生錯誤: {error}" "error": "關閉 Cursor 進程時發生錯誤: {error}"
}, },
"reset": {
"title": "Cursor 機器標識重置工具",
"checking": "檢查配置文件",
"not_found": "配置文件未找到",
"no_permission": "無法讀取或寫入配置文件,請檢查文件權限",
"reading": "讀取當前配置",
"creating_backup": "創建配置備份",
"backup_exists": "備份文件已存在,跳過備份步驟",
"generating": "生成新機器標識",
"saving_json": "保存新配置到JSON",
"success": "機器標識重置成功",
"new_id": "新機器標識",
"permission_error": "權限錯誤: {error}",
"run_as_admin": "請嘗試以管理員身份運行此程序",
"process_error": "重置進程錯誤: {error}",
"updating_sqlite": "更新SQLite數據庫",
"updating_pair": "更新鍵值對",
"sqlite_success": "SQLite數據庫更新成功",
"sqlite_error": "SQLite數據庫更新失敗: {error}",
"press_enter": "按回車鍵退出",
"updating_system_ids": "更新系統ID",
"system_ids_updated": "系統ID更新成功",
"system_ids_update_failed": "系統ID更新失敗: {error}",
"unsupported_os": "不支持的操作系統: {os}",
"linux_path_not_found": "Linux路徑未找到",
"windows_guid_updated": "Windows GUID更新成功",
"windows_permission_denied": "Windows權限拒絕",
"windows_guid_update_failed": "Windows GUID更新失敗",
"macos_uuid_updated": "macOS UUID更新成功",
"plutil_command_failed": "plutil命令失敗",
"macos_uuid_update_failed": "macOS UUID更新失敗",
"start_patching": "開始修補getMachineId",
"current_version": "當前Cursor版本: {version}",
"patch_completed": "getMachineId修補完成",
"patch_failed": "getMachineId修補失敗: {error}",
"version_check_passed": "Cursor版本檢查通過",
"file_modified": "文件已修改"
},
"register": { "register": {
"title": "Cursor 註冊工具", "title": "Cursor 註冊工具",
"start": "開始註冊流程", "start": "開始註冊流程",
@@ -68,7 +110,8 @@
"account_info_saved": "賬戶信息已保存", "account_info_saved": "賬戶信息已保存",
"save_account_info_failed": "保存賬戶信息失敗", "save_account_info_failed": "保存賬戶信息失敗",
"get_email_address": "獲取郵箱地址", "get_email_address": "獲取郵箱地址",
"register_process_error": "註冊流程錯誤: {error}" "register_process_error": "註冊流程錯誤: {error}",
"update_cursor_auth_info": "更新Cursor認證信息"
}, },
"auth": { "auth": {
"title": "Cursor 認證管理器", "title": "Cursor 認證管理器",
@@ -81,7 +124,11 @@
"auth_update_failed": "認證信息更新失敗: {error}", "auth_update_failed": "認證信息更新失敗: {error}",
"auth_file_created": "認證文件已創建", "auth_file_created": "認證文件已創建",
"auth_file_create_failed": "認證文件創建失敗: {error}", "auth_file_create_failed": "認證文件創建失敗: {error}",
"press_enter": "按回車鍵退出" "press_enter": "按回車鍵退出",
"connected_to_database": "已連接到數據庫",
"database_updated_successfully": "數據庫更新成功",
"database_connection_closed": "數據庫連接已關閉",
"updating_pair": "更新鍵值對"
}, },
"control": { "control": {
"generate_email": "生成新郵箱", "generate_email": "生成新郵箱",

11
logo.py
View File

@@ -2,8 +2,14 @@ from colorama import Fore, Style, init
from dotenv import load_dotenv from dotenv import load_dotenv
import os import os
# 加載環境變量獲取版本號 # 獲取當前腳本所在目錄
load_dotenv() current_dir = os.path.dirname(os.path.abspath(__file__))
# 構建.env文件的完整路徑
env_path = os.path.join(current_dir, '.env')
# 加載環境變量,指定.env文件路徑
load_dotenv(env_path)
# 獲取版本號,如果未找到則使用默認值
version = os.getenv('VERSION', '1.0.0') version = os.getenv('VERSION', '1.0.0')
# 初始化 colorama # 初始化 colorama
@@ -29,6 +35,5 @@ CURSOR_LOGO = f"""
def print_logo(): def print_logo():
print(CURSOR_LOGO) print(CURSOR_LOGO)
if __name__ == "__main__": if __name__ == "__main__":
print_logo() print_logo()

16
main.py
View File

@@ -42,11 +42,17 @@ class Translator:
def get(self, key, **kwargs): def get(self, key, **kwargs):
"""获取翻译文本""" """获取翻译文本"""
keys = key.split('.') try:
value = self.translations.get(self.current_language, {}) keys = key.split('.')
for k in keys: value = self.translations.get(self.current_language, {})
value = value.get(k, key) for k in keys:
return value.format(**kwargs) if kwargs else value if isinstance(value, dict):
value = value.get(k, key)
else:
return key # 如果中間值不是字典返回原始key
return value.format(**kwargs) if kwargs else value
except Exception:
return key # 出現任何錯誤時返回原始key
def set_language(self, lang_code): def set_language(self, lang_code):
"""设置当前语言""" """设置当前语言"""

View File

@@ -5,7 +5,11 @@ import uuid
import hashlib import hashlib
import shutil import shutil
import sqlite3 import sqlite3
import platform
import re
import tempfile
from colorama import Fore, Style, init from colorama import Fore, Style, init
from typing import Tuple
# 初始化colorama # 初始化colorama
init() init()
@@ -20,6 +24,173 @@ EMOJI = {
"RESET": "🔄", "RESET": "🔄",
} }
def get_cursor_paths(translator=None) -> Tuple[str, str]:
"""根据不同操作系统获取 Cursor 相关路径"""
system = platform.system()
paths_map = {
"Darwin": {
"base": "/Applications/Cursor.app/Contents/Resources/app",
"package": "package.json",
"main": "out/main.js",
},
"Windows": {
"base": os.path.join(
os.getenv("LOCALAPPDATA", ""), "Programs", "Cursor", "resources", "app"
),
"package": "package.json",
"main": "out/main.js",
},
"Linux": {
"bases": ["/opt/Cursor/resources/app", "/usr/share/cursor/resources/app"],
"package": "package.json",
"main": "out/main.js",
},
}
if system not in paths_map:
raise OSError(translator.get('reset.unsupported_os', system=system) if translator else f"不支持的操作系统: {system}")
if system == "Linux":
for base in paths_map["Linux"]["bases"]:
pkg_path = os.path.join(base, paths_map["Linux"]["package"])
if os.path.exists(pkg_path):
return (pkg_path, os.path.join(base, paths_map["Linux"]["main"]))
raise OSError(translator.get('reset.linux_path_not_found') if translator else "在 Linux 系统上未找到 Cursor 安装路径")
base_path = paths_map[system]["base"]
return (
os.path.join(base_path, paths_map[system]["package"]),
os.path.join(base_path, paths_map[system]["main"]),
)
def version_check(version: str, min_version: str = "", max_version: str = "", translator=None) -> bool:
"""版本号检查"""
version_pattern = r"^\d+\.\d+\.\d+$"
try:
if not re.match(version_pattern, version):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.invalid_version_format', version=version)}{Style.RESET_ALL}")
return False
def parse_version(ver: str) -> Tuple[int, ...]:
return tuple(map(int, ver.split(".")))
current = parse_version(version)
if min_version and current < parse_version(min_version):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.version_too_low', version=version, min_version=min_version)}{Style.RESET_ALL}")
return False
if max_version and current > parse_version(max_version):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.version_too_high', version=version, max_version=max_version)}{Style.RESET_ALL}")
return False
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.version_check_error', error=str(e))}{Style.RESET_ALL}")
return False
def check_cursor_version(translator) -> bool:
"""检查 Cursor 版本"""
try:
pkg_path, _ = get_cursor_paths(translator)
with open(pkg_path, "r", encoding="utf-8") as f:
version = json.load(f)["version"]
return version_check(version, min_version="0.45.0", translator=translator)
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.check_version_failed', error=str(e))}{Style.RESET_ALL}")
return False
def modify_main_js(main_path: str, translator) -> bool:
"""修改 main.js 文件"""
try:
original_stat = os.stat(main_path)
original_mode = original_stat.st_mode
original_uid = original_stat.st_uid
original_gid = original_stat.st_gid
with tempfile.NamedTemporaryFile(mode="w", delete=False) as tmp_file:
with open(main_path, "r", encoding="utf-8") as main_file:
content = main_file.read()
patterns = {
r"async getMachineId\(\)\{return [^??]+\?\?([^}]+)\}": r"async getMachineId(){return \1}",
r"async getMacMachineId\(\)\{return [^??]+\?\?([^}]+)\}": r"async getMacMachineId(){return \1}",
}
for pattern, replacement in patterns.items():
content = re.sub(pattern, replacement, content)
tmp_file.write(content)
tmp_path = tmp_file.name
shutil.copy2(main_path, main_path + ".old")
shutil.move(tmp_path, main_path)
os.chmod(main_path, original_mode)
if os.name != "nt":
os.chown(main_path, original_uid, original_gid)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.file_modified')}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.modify_file_failed', error=str(e))}{Style.RESET_ALL}")
if "tmp_path" in locals():
os.unlink(tmp_path)
return False
def patch_cursor_get_machine_id(translator) -> bool:
"""修补 Cursor getMachineId 函数"""
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.start_patching')}...{Style.RESET_ALL}")
# 获取路径
pkg_path, main_path = get_cursor_paths(translator)
# 检查文件权限
for file_path in [pkg_path, main_path]:
if not os.path.isfile(file_path):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.file_not_found', path=file_path)}{Style.RESET_ALL}")
return False
if not os.access(file_path, os.W_OK):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.no_write_permission', path=file_path)}{Style.RESET_ALL}")
return False
# 获取版本号
try:
with open(pkg_path, "r", encoding="utf-8") as f:
version = json.load(f)["version"]
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.current_version', version=version)}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.read_version_failed', error=str(e))}{Style.RESET_ALL}")
return False
# 检查版本
if not version_check(version, min_version="0.45.0", translator=translator):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.version_not_supported')}{Style.RESET_ALL}")
return False
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.version_check_passed')}{Style.RESET_ALL}")
# 备份文件
backup_path = main_path + ".bak"
if not os.path.exists(backup_path):
shutil.copy2(main_path, backup_path)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.backup_created', path=backup_path)}{Style.RESET_ALL}")
# 修改文件
if not modify_main_js(main_path, translator):
return False
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.patch_completed')}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.patch_failed', error=str(e))}{Style.RESET_ALL}")
return False
class MachineIDResetter: class MachineIDResetter:
def __init__(self, translator=None): def __init__(self, translator=None):
self.translator = translator self.translator = translator
@@ -98,7 +269,7 @@ class MachineIDResetter:
INSERT OR REPLACE INTO ItemTable (key, value) INSERT OR REPLACE INTO ItemTable (key, value)
VALUES (?, ?) VALUES (?, ?)
""", (key, value)) """, (key, value))
print(f"{EMOJI['INFO']} {Fore.CYAN}{self.translator.get('reset.updating_pair')}: {key}{Style.RESET_ALL}") print(f"{EMOJI['INFO']} {Fore.CYAN} {self.translator.get('reset.updating_pair')}: {key}{Style.RESET_ALL}")
conn.commit() conn.commit()
conn.close() conn.close()
@@ -109,6 +280,59 @@ class MachineIDResetter:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.sqlite_error', error=str(e))}{Style.RESET_ALL}") print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.sqlite_error', error=str(e))}{Style.RESET_ALL}")
return False return False
def update_system_ids(self, new_ids):
"""更新系统级别的ID"""
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.updating_system_ids')}...{Style.RESET_ALL}")
if sys.platform.startswith("win"):
self._update_windows_machine_guid()
elif sys.platform == "darwin":
self._update_macos_platform_uuid(new_ids)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.system_ids_updated')}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.system_ids_update_failed', error=str(e))}{Style.RESET_ALL}")
return False
def _update_windows_machine_guid(self):
"""更新Windows MachineGuid"""
try:
import winreg
key = winreg.OpenKey(
winreg.HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Cryptography",
0,
winreg.KEY_WRITE | winreg.KEY_WOW64_64KEY
)
new_guid = str(uuid.uuid4())
winreg.SetValueEx(key, "MachineGuid", 0, winreg.REG_SZ, new_guid)
winreg.CloseKey(key)
print("Windows MachineGuid updated successfully")
except PermissionError:
print("Permission denied: Run as administrator to update Windows MachineGuid")
raise
except Exception as e:
print(f"Failed to update Windows MachineGuid: {e}")
raise
def _update_macos_platform_uuid(self, new_ids):
"""更新macOS Platform UUID"""
try:
uuid_file = "/var/root/Library/Preferences/SystemConfiguration/com.apple.platform.uuid.plist"
if os.path.exists(uuid_file):
# 使用sudo来执行plutil命令
cmd = f'sudo plutil -replace "UUID" -string "{new_ids["telemetry.macMachineId"]}" "{uuid_file}"'
result = os.system(cmd)
if result == 0:
print("macOS Platform UUID updated successfully")
else:
raise Exception("Failed to execute plutil command")
except Exception as e:
print(f"Failed to update macOS Platform UUID: {e}")
raise
def reset_machine_ids(self): def reset_machine_ids(self):
"""重置机器ID并备份原文件""" """重置机器ID并备份原文件"""
try: try:
@@ -136,14 +360,27 @@ class MachineIDResetter:
print(f"{Fore.CYAN}{EMOJI['RESET']} {self.translator.get('reset.generating')}...{Style.RESET_ALL}") print(f"{Fore.CYAN}{EMOJI['RESET']} {self.translator.get('reset.generating')}...{Style.RESET_ALL}")
new_ids = self.generate_new_ids() new_ids = self.generate_new_ids()
# 更新配置文件
config.update(new_ids) config.update(new_ids)
print(f"{Fore.CYAN}{EMOJI['FILE']} {self.translator.get('reset.saving_json')}...{Style.RESET_ALL}") print(f"{Fore.CYAN}{EMOJI['FILE']} {self.translator.get('reset.saving_json')}...{Style.RESET_ALL}")
with open(self.db_path, "w", encoding="utf-8") as f: with open(self.db_path, "w", encoding="utf-8") as f:
json.dump(config, f, indent=4) json.dump(config, f, indent=4)
# 更新SQLite数据库
self.update_sqlite_db(new_ids) self.update_sqlite_db(new_ids)
# 更新系统ID
self.update_system_ids(new_ids)
# 检查 Cursor 版本并执行相应的操作
greater_than_0_45 = check_cursor_version(self.translator)
if greater_than_0_45:
print(f"{Fore.CYAN}{EMOJI['INFO']} 检测到 Cursor 版本 >= 0.45.0,正在修补 getMachineId...{Style.RESET_ALL}")
patch_cursor_get_machine_id(self.translator)
else:
print(f"{Fore.YELLOW}{EMOJI['INFO']} Cursor 版本 < 0.45.0,跳过 getMachineId 修补{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.success')}{Style.RESET_ALL}") print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.success')}{Style.RESET_ALL}")
print(f"\n{Fore.CYAN}{self.translator.get('reset.new_id')}:{Style.RESET_ALL}") print(f"\n{Fore.CYAN}{self.translator.get('reset.new_id')}:{Style.RESET_ALL}")
for key, value in new_ids.items(): for key, value in new_ids.items():
@@ -160,18 +397,17 @@ class MachineIDResetter:
return False return False
def run(translator=None): def run(translator=None):
"""Main function to be called from main.py""" """便捷函数,用于直接调用重置功能"""
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}")
resetter = MachineIDResetter(translator) resetter = MachineIDResetter(translator) # 正確傳遞 translator
resetter.reset_machine_ids() resetter.reset_machine_ids()
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}") print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
input(f"{EMOJI['INFO']} {translator.get('reset.press_enter')}...") input(f"{EMOJI['INFO']} {translator.get('reset.press_enter')}...")
if __name__ == "__main__": if __name__ == "__main__":
# 如果直接运行,使用默认翻译器
from main import translator as main_translator from main import translator as main_translator
run(main_translator) run(main_translator)