mirror of
https://github.com/yeongpin/cursor-free-vip.git
synced 2025-08-03 04:57:36 +08:00
Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1c36ff010e | ||
![]() |
4f060abc93 | ||
![]() |
e8ab5654ad | ||
![]() |
f9e3c6025b | ||
![]() |
d02e5d69c8 | ||
![]() |
849de8fac2 | ||
![]() |
201557d79c | ||
![]() |
30418e36a5 | ||
![]() |
c3a3963a76 | ||
![]() |
baec0937c3 | ||
![]() |
bdbec76a7b | ||
![]() |
3386d8e08e | ||
![]() |
cb9ec64388 | ||
![]() |
76179807bc | ||
![]() |
f8499708c9 | ||
![]() |
4a459574ad | ||
![]() |
2d1604c646 | ||
![]() |
be950c510c | ||
![]() |
e190a81ee4 | ||
![]() |
fa74b17dce | ||
![]() |
db490718c5 |
@ -1,5 +1,10 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## v1.11.03
|
||||||
|
1. Update: TempMailPlus Cursor Email Detection Logic | 更新 TempMailPlus Cursor 邮件识别逻辑
|
||||||
|
2. Fix: Windows User Directory Path | 修正 windows 环境下用户目录的获取方式
|
||||||
|
3. Fix: Some Issues | 修復一些問題
|
||||||
|
|
||||||
## v1.11.02
|
## v1.11.02
|
||||||
1. Fill: Missing Translations(ar, zh-cn, zh-tw, vi, nl, de, fr, pt, ru, tr, bg, es, ja, it) | 填補缺失的翻譯
|
1. Fill: Missing Translations(ar, zh-cn, zh-tw, vi, nl, de, fr, pt, ru, tr, bg, es, ja, it) | 填補缺失的翻譯
|
||||||
2. Add: Japanese and Italian language support
|
2. Add: Japanese and Italian language support
|
||||||
|
@ -159,6 +159,14 @@ check_update = True
|
|||||||
# Show Account Info | 顯示賬號信息
|
# Show Account Info | 顯示賬號信息
|
||||||
show_account_info = True
|
show_account_info = True
|
||||||
|
|
||||||
|
[TempMailPlus]
|
||||||
|
# Enable TempMailPlus | 啓用 TempMailPlus(任何轉發到TempMailPlus的郵件都支持獲取驗證碼,例如cloudflare郵件Catch-all)
|
||||||
|
enabled = false
|
||||||
|
# TempMailPlus Email | TempMailPlus 電子郵件
|
||||||
|
email = xxxxx@mailto.plus
|
||||||
|
# TempMailPlus pin | TempMailPlus pin碼
|
||||||
|
epin =
|
||||||
|
|
||||||
[WindowsPaths]
|
[WindowsPaths]
|
||||||
storage_path = C:\Users\yeongpin\AppData\Roaming\Cursor\User\globalStorage\storage.json
|
storage_path = C:\Users\yeongpin\AppData\Roaming\Cursor\User\globalStorage\storage.json
|
||||||
sqlite_path = C:\Users\yeongpin\AppData\Roaming\Cursor\User\globalStorage\state.vscdb
|
sqlite_path = C:\Users\yeongpin\AppData\Roaming\Cursor\User\globalStorage\state.vscdb
|
||||||
|
97
account_manager.py
Normal file
97
account_manager.py
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import os
|
||||||
|
from colorama import Fore, Style
|
||||||
|
import re
|
||||||
|
|
||||||
|
# Define emoji constants
|
||||||
|
EMOJI = {
|
||||||
|
'SUCCESS': '✅',
|
||||||
|
'ERROR': '❌',
|
||||||
|
'INFO': 'ℹ️'
|
||||||
|
}
|
||||||
|
|
||||||
|
class AccountManager:
|
||||||
|
def __init__(self, translator=None):
|
||||||
|
self.translator = translator
|
||||||
|
self.accounts_file = 'cursor_accounts.txt'
|
||||||
|
|
||||||
|
def save_account_info(self, email, password, token, total_usage):
|
||||||
|
"""Save account information to file"""
|
||||||
|
try:
|
||||||
|
with open(self.accounts_file, 'a', encoding='utf-8') as f:
|
||||||
|
f.write(f"\n{'='*50}\n")
|
||||||
|
f.write(f"Email: {email}\n")
|
||||||
|
f.write(f"Password: {password}\n")
|
||||||
|
f.write(f"Token: {token}\n")
|
||||||
|
f.write(f"Usage Limit: {total_usage}\n")
|
||||||
|
f.write(f"{'='*50}\n")
|
||||||
|
|
||||||
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.account_info_saved') if self.translator else 'Account information saved'}...{Style.RESET_ALL}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = self.translator.get('register.save_account_info_failed', error=str(e)) if self.translator else f'Failed to save account information: {str(e)}'
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {error_msg}{Style.RESET_ALL}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_last_email_domain(self):
|
||||||
|
"""Get the domain from the last used email"""
|
||||||
|
try:
|
||||||
|
if not os.path.exists(self.accounts_file):
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Only read the last 1KB of data from the file
|
||||||
|
with open(self.accounts_file, 'rb') as f:
|
||||||
|
# Get file size
|
||||||
|
f.seek(0, os.SEEK_END)
|
||||||
|
file_size = f.tell()
|
||||||
|
|
||||||
|
if file_size == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Determine the number of bytes to read, maximum 1KB
|
||||||
|
read_size = min(1024, file_size)
|
||||||
|
|
||||||
|
# Move to the appropriate position to start reading
|
||||||
|
f.seek(file_size - read_size)
|
||||||
|
|
||||||
|
# Read the end data
|
||||||
|
data = f.read(read_size).decode('utf-8', errors='ignore')
|
||||||
|
|
||||||
|
# Split by lines and search in reverse
|
||||||
|
lines = data.split('\n')
|
||||||
|
for line in reversed(lines):
|
||||||
|
if line.strip().startswith('Email:'):
|
||||||
|
email = line.split('Email:')[1].strip()
|
||||||
|
# Extract domain part (after @)
|
||||||
|
if '@' in email:
|
||||||
|
return email.split('@')[1]
|
||||||
|
return None
|
||||||
|
|
||||||
|
# If no email is found in the last 1KB
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = self.translator.get('account.get_last_email_domain_failed', error=str(e)) if self.translator else f'Failed to get the last used email domain: {str(e)}'
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {error_msg}{Style.RESET_ALL}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def suggest_email(self, first_name, last_name):
|
||||||
|
"""Generate a suggested email based on first and last name with the last used domain"""
|
||||||
|
try:
|
||||||
|
# Get the last used email domain
|
||||||
|
domain = self.get_last_email_domain()
|
||||||
|
if not domain:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Generate email prefix from first and last name (lowercase)
|
||||||
|
email_prefix = f"{first_name.lower()}.{last_name.lower()}"
|
||||||
|
|
||||||
|
# Combine prefix and domain
|
||||||
|
suggested_email = f"{email_prefix}@{domain}"
|
||||||
|
|
||||||
|
return suggested_email
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = self.translator.get('account.suggest_email_failed', error=str(e)) if self.translator else f'Failed to suggest email: {str(e)}'
|
||||||
|
print(f"{Fore.RED}{EMOJI['ERROR']} {error_msg}{Style.RESET_ALL}")
|
||||||
|
return None
|
@ -26,6 +26,13 @@ EMOJI = {
|
|||||||
def get_user_documents_path():
|
def get_user_documents_path():
|
||||||
"""Get user Documents folder path"""
|
"""Get user Documents folder path"""
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
|
try:
|
||||||
|
import winreg
|
||||||
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders") as key:
|
||||||
|
documents_path, _ = winreg.QueryValueEx(key, "Personal")
|
||||||
|
return documents_path
|
||||||
|
except Exception as e:
|
||||||
|
# fallback
|
||||||
return os.path.join(os.path.expanduser("~"), "Documents")
|
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||||
elif sys.platform == "darwin":
|
elif sys.platform == "darwin":
|
||||||
return os.path.join(os.path.expanduser("~"), "Documents")
|
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||||
|
59804
cursor-source-map/0.50.5/core/main.js.map
Normal file
59804
cursor-source-map/0.50.5/core/main.js.map
Normal file
File diff suppressed because one or more lines are too long
971088
cursor-source-map/0.50.5/core/vs/workbench/workbench.desktop.main.js.map
Normal file
971088
cursor-source-map/0.50.5/core/vs/workbench/workbench.desktop.main.js.map
Normal file
File diff suppressed because one or more lines are too long
@ -7,6 +7,7 @@ from cursor_auth import CursorAuth
|
|||||||
from reset_machine_manual import MachineIDResetter
|
from reset_machine_manual import MachineIDResetter
|
||||||
from get_user_token import get_token_from_cookie
|
from get_user_token import get_token_from_cookie
|
||||||
from config import get_config
|
from config import get_config
|
||||||
|
from account_manager import AccountManager
|
||||||
|
|
||||||
os.environ["PYTHONVERBOSE"] = "0"
|
os.environ["PYTHONVERBOSE"] = "0"
|
||||||
os.environ["PYINSTALLER_VERBOSE"] = "0"
|
os.environ["PYINSTALLER_VERBOSE"] = "0"
|
||||||
@ -67,11 +68,28 @@ class CursorRegistration:
|
|||||||
def setup_email(self):
|
def setup_email(self):
|
||||||
"""Setup Email"""
|
"""Setup Email"""
|
||||||
try:
|
try:
|
||||||
|
# Try to get a suggested email
|
||||||
|
account_manager = AccountManager(self.translator)
|
||||||
|
suggested_email = account_manager.suggest_email(self.first_name, self.last_name)
|
||||||
|
|
||||||
|
if suggested_email:
|
||||||
|
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.suggest_email', suggested_email=suggested_email) if self.translator else f'Suggested email: {suggested_email}'}")
|
||||||
|
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.use_suggested_email_or_enter') if self.translator else 'Type "yes" to use this email or enter your own email:'}")
|
||||||
|
user_input = input().strip()
|
||||||
|
|
||||||
|
if user_input.lower() == 'yes' or user_input.lower() == 'y':
|
||||||
|
self.email_address = suggested_email
|
||||||
|
else:
|
||||||
|
# User input is their own email address
|
||||||
|
self.email_address = user_input
|
||||||
|
else:
|
||||||
|
# If there's no suggested email
|
||||||
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.manual_email_input') if self.translator else 'Please enter your email address:'}")
|
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.manual_email_input') if self.translator else 'Please enter your email address:'}")
|
||||||
self.email_address = input().strip()
|
self.email_address = input().strip()
|
||||||
|
|
||||||
|
# Validate if the email is valid
|
||||||
if '@' not in self.email_address:
|
if '@' not in self.email_address:
|
||||||
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 'Invalid email address'}{Style.RESET_ALL}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('register.email_address')}: {self.email_address}" + "\n" + f"{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('register.email_address')}: {self.email_address}" + "\n" + f"{Style.RESET_ALL}")
|
||||||
@ -88,7 +106,7 @@ class CursorRegistration:
|
|||||||
code = input().strip()
|
code = input().strip()
|
||||||
|
|
||||||
if not code.isdigit() or len(code) != 6:
|
if not code.isdigit() or len(code) != 6:
|
||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.invalid_code') if self.translator else '无效的验证码'}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.invalid_code') if self.translator else 'Invalid verification code'}{Style.RESET_ALL}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return code
|
return code
|
||||||
@ -112,7 +130,7 @@ class CursorRegistration:
|
|||||||
epin = config.get('TempMailPlus', 'epin')
|
epin = config.get('TempMailPlus', 'epin')
|
||||||
if email and epin:
|
if email and epin:
|
||||||
from email_tabs.tempmail_plus_tab import TempMailPlusTab
|
from email_tabs.tempmail_plus_tab import TempMailPlusTab
|
||||||
email_tab = TempMailPlusTab(email, epin)
|
email_tab = TempMailPlusTab(email, epin, self.translator)
|
||||||
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('register.using_tempmail_plus')}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('register.using_tempmail_plus')}{Style.RESET_ALL}")
|
||||||
|
|
||||||
# Use new_signup.py directly for registration
|
# Use new_signup.py directly for registration
|
||||||
@ -224,17 +242,12 @@ class CursorRegistration:
|
|||||||
if not resetter.reset_machine_ids(): # Call reset_machine_ids method directly
|
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 using AccountManager
|
||||||
with open('cursor_accounts.txt', 'a', encoding='utf-8') as f:
|
account_manager = AccountManager(self.translator)
|
||||||
f.write(f"\n{'='*50}\n")
|
if account_manager.save_account_info(self.email_address, self.password, token, total_usage):
|
||||||
f.write(f"Email: {self.email_address}\n")
|
|
||||||
f.write(f"Password: {self.password}\n")
|
|
||||||
f.write(f"Token: {token}\n")
|
|
||||||
f.write(f"Usage Limit: {total_usage}\n")
|
|
||||||
f.write(f"{'='*50}\n")
|
|
||||||
|
|
||||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.account_info_saved')}...{Style.RESET_ALL}")
|
|
||||||
return True
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.save_account_info_failed', error=str(e))}{Style.RESET_ALL}")
|
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.save_account_info_failed', error=str(e))}{Style.RESET_ALL}")
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
class EmailTabInterface(ABC):
|
class EmailTabInterface(ABC):
|
||||||
"""Email tab interface for handling email verification"""
|
"""Interface for email tab implementations"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def refresh_inbox(self) -> None:
|
def refresh_inbox(self) -> None:
|
||||||
@ -10,10 +10,10 @@ class EmailTabInterface(ABC):
|
|||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def check_for_cursor_email(self) -> bool:
|
def check_for_cursor_email(self) -> bool:
|
||||||
"""Check if there is a verification email from Cursor
|
"""Check if there is a new email from Cursor
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if verification email exists, False otherwise
|
bool: True if new email found, False otherwise
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -22,6 +22,6 @@ class EmailTabInterface(ABC):
|
|||||||
"""Get the verification code from the email
|
"""Get the verification code from the email
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: The verification code if found, empty string otherwise
|
str: The verification code if available, empty string otherwise
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
@ -1,20 +1,27 @@
|
|||||||
import requests
|
import requests
|
||||||
import re
|
import re
|
||||||
|
import datetime
|
||||||
|
import time
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from .email_tab_interface import EmailTabInterface
|
from .email_tab_interface import EmailTabInterface
|
||||||
|
|
||||||
class TempMailPlusTab(EmailTabInterface):
|
class TempMailPlusTab(EmailTabInterface):
|
||||||
"""Implementation of EmailTabInterface for tempmail.plus"""
|
"""Implementation of EmailTabInterface for tempmail.plus"""
|
||||||
|
|
||||||
def __init__(self, email: str, epin: str):
|
def __init__(self, email: str, epin: str, translator=None,
|
||||||
|
polling_interval: int = 2, max_attempts: int = 10):
|
||||||
"""Initialize TempMailPlusTab
|
"""Initialize TempMailPlusTab
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
email: The email address to check
|
email: The email address to check
|
||||||
epin: The epin token for authentication
|
epin: The epin token for authentication
|
||||||
|
translator: Optional translator for internationalization
|
||||||
|
polling_interval: Time in seconds between polling attempts
|
||||||
|
max_attempts: Maximum number of polling attempts
|
||||||
"""
|
"""
|
||||||
self.email = email
|
self.email = email
|
||||||
self.epin = epin
|
self.epin = epin
|
||||||
|
self.translator = translator
|
||||||
self.base_url = "https://tempmail.plus/api"
|
self.base_url = "https://tempmail.plus/api"
|
||||||
self.headers = {
|
self.headers = {
|
||||||
'accept': 'application/json',
|
'accept': 'application/json',
|
||||||
@ -32,17 +39,59 @@ class TempMailPlusTab(EmailTabInterface):
|
|||||||
'x-requested-with': 'XMLHttpRequest'
|
'x-requested-with': 'XMLHttpRequest'
|
||||||
}
|
}
|
||||||
self.cookies = {'email': email}
|
self.cookies = {'email': email}
|
||||||
self._cached_mail_id = None # 缓存mail_id
|
self._cached_mail_id = None # Cache for mail_id
|
||||||
|
self._cached_verification_code = None # Cache for verification code
|
||||||
|
|
||||||
|
# Polling configuration
|
||||||
|
self.polling_interval = polling_interval
|
||||||
|
self.max_attempts = max_attempts
|
||||||
|
self.current_attempt = 0
|
||||||
|
|
||||||
def refresh_inbox(self) -> None:
|
def refresh_inbox(self) -> None:
|
||||||
"""Refresh the email inbox"""
|
"""Refresh the email inbox"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def check_for_cursor_email(self) -> bool:
|
def check_for_cursor_email(self) -> bool:
|
||||||
"""Check if there is a verification email from Cursor
|
"""Check if there is a new email and immediately retrieve verification code
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if verification email exists, False otherwise
|
bool: True if new email found and verification code retrieved, False otherwise
|
||||||
|
"""
|
||||||
|
# Reset attempt counter
|
||||||
|
self.current_attempt = 0
|
||||||
|
|
||||||
|
# Polling logic
|
||||||
|
while self.current_attempt < self.max_attempts:
|
||||||
|
found = self._check_email_once()
|
||||||
|
if found:
|
||||||
|
# Successfully found email and retrieved verification code
|
||||||
|
self.current_attempt = 0 # Reset counter for next use
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Not found, continue polling
|
||||||
|
self.current_attempt += 1
|
||||||
|
if self.current_attempt < self.max_attempts:
|
||||||
|
# Print polling status information
|
||||||
|
if self.translator:
|
||||||
|
print(self.translator.get('tempmail.polling',
|
||||||
|
attempt=self.current_attempt,
|
||||||
|
max=self.max_attempts))
|
||||||
|
else:
|
||||||
|
print(f"Polling for email: attempt {self.current_attempt}/{self.max_attempts}")
|
||||||
|
time.sleep(self.polling_interval)
|
||||||
|
|
||||||
|
# Exceeded maximum attempts
|
||||||
|
if self.translator:
|
||||||
|
print(self.translator.get('tempmail.max_attempts_reached'))
|
||||||
|
else:
|
||||||
|
print(f"Max attempts ({self.max_attempts}) reached. No verification email found.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _check_email_once(self) -> bool:
|
||||||
|
"""Single attempt to check for email
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if new email found and verification code retrieved, False otherwise
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
params = {
|
params = {
|
||||||
@ -59,28 +108,30 @@ class TempMailPlusTab(EmailTabInterface):
|
|||||||
|
|
||||||
data = response.json()
|
data = response.json()
|
||||||
if data.get('result') and data.get('mail_list'):
|
if data.get('result') and data.get('mail_list'):
|
||||||
for mail in data['mail_list']:
|
# Check if the first email in the list is a new email
|
||||||
if 'cursor.sh' in mail.get('from_mail', '') and mail.get('is_new') == True:
|
if data['mail_list'][0].get('is_new') == True:
|
||||||
self._cached_mail_id = mail.get('mail_id') # 缓存mail_id
|
self._cached_mail_id = data['mail_list'][0].get('mail_id') # Cache the mail_id
|
||||||
|
|
||||||
|
# Immediately retrieve verification code
|
||||||
|
verification_code = self._extract_verification_code()
|
||||||
|
if verification_code:
|
||||||
|
self._cached_verification_code = verification_code
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"检查Cursor邮件失败: {str(e)}")
|
print(f"{self.translator.get('tempmail.check_email_failed', error=str(e)) if self.translator else f'Check email failed: {str(e)}'}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_verification_code(self) -> str:
|
def _extract_verification_code(self) -> str:
|
||||||
"""Get the verification code from the email
|
"""Extract verification code from email content
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: The verification code if found, empty string otherwise
|
str: The verification code if found, empty string otherwise
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# 如果没有缓存的mail_id,先检查是否有新邮件
|
|
||||||
if not self._cached_mail_id:
|
if not self._cached_mail_id:
|
||||||
if not self.check_for_cursor_email():
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
# 使用缓存的mail_id获取邮件内容
|
|
||||||
params = {
|
params = {
|
||||||
'email': self.email,
|
'email': self.email,
|
||||||
'epin': self.epin
|
'epin': self.epin
|
||||||
@ -97,6 +148,11 @@ class TempMailPlusTab(EmailTabInterface):
|
|||||||
if not data.get('result'):
|
if not data.get('result'):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
# Verify if sender email contains cursor string
|
||||||
|
from_mail = data.get('from_mail', '')
|
||||||
|
if 'cursor' not in from_mail.lower():
|
||||||
|
return ""
|
||||||
|
|
||||||
# Extract verification code from text content using regex
|
# Extract verification code from text content using regex
|
||||||
text = data.get('text', '')
|
text = data.get('text', '')
|
||||||
match = re.search(r'\n\n(\d{6})\n\n', text)
|
match = re.search(r'\n\n(\d{6})\n\n', text)
|
||||||
@ -105,5 +161,57 @@ class TempMailPlusTab(EmailTabInterface):
|
|||||||
|
|
||||||
return ""
|
return ""
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"获取验证码失败: {str(e)}")
|
print(f"{self.translator.get('tempmail.extract_code_failed', error=str(e)) if self.translator else f'Extract verification code failed: {str(e)}'}")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
def get_verification_code(self) -> str:
|
||||||
|
"""Get the verification code from cache
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The cached verification code if available, empty string otherwise
|
||||||
|
"""
|
||||||
|
return self._cached_verification_code or ""
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import configparser
|
||||||
|
|
||||||
|
from config import get_config
|
||||||
|
|
||||||
|
# Try to import translator
|
||||||
|
try:
|
||||||
|
from main import Translator
|
||||||
|
translator = Translator()
|
||||||
|
except ImportError:
|
||||||
|
translator = None
|
||||||
|
|
||||||
|
config = get_config(translator)
|
||||||
|
|
||||||
|
try:
|
||||||
|
email = config.get('TempMailPlus', 'email')
|
||||||
|
epin = config.get('TempMailPlus', 'epin')
|
||||||
|
|
||||||
|
print(f"{translator.get('tempmail.configured_email', email=email) if translator else f'Configured email: {email}'}")
|
||||||
|
|
||||||
|
# Initialize TempMailPlusTab, pass translator
|
||||||
|
mail_tab = TempMailPlusTab(email, epin, translator)
|
||||||
|
|
||||||
|
# Check if there is a Cursor email
|
||||||
|
print(f"{translator.get('tempmail.checking_email') if translator else 'Checking for Cursor verification email...'}")
|
||||||
|
if mail_tab.check_for_cursor_email():
|
||||||
|
print(f"{translator.get('tempmail.email_found') if translator else 'Found Cursor verification email'}")
|
||||||
|
|
||||||
|
# Get verification code
|
||||||
|
verification_code = mail_tab.get_verification_code()
|
||||||
|
if verification_code:
|
||||||
|
print(f"{translator.get('tempmail.verification_code', code=verification_code) if translator else f'Verification code: {verification_code}'}")
|
||||||
|
else:
|
||||||
|
print(f"{translator.get('tempmail.no_code') if translator else 'Could not get verification code'}")
|
||||||
|
else:
|
||||||
|
print(f"{translator.get('tempmail.no_email') if translator else 'No Cursor verification email found'}")
|
||||||
|
|
||||||
|
except configparser.Error as e:
|
||||||
|
print(f"{translator.get('tempmail.config_error', error=str(e)) if translator else f'Config file error: {str(e)}'}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{translator.get('tempmail.general_error', error=str(e)) if translator else f'An error occurred: {str(e)}'}")
|
@ -850,5 +850,17 @@
|
|||||||
"updating_database": "تحديث قاعدة بيانات مصادقة المؤشر ...",
|
"updating_database": "تحديث قاعدة بيانات مصادقة المؤشر ...",
|
||||||
"title": "مصادقة المؤشر اليدوي",
|
"title": "مصادقة المؤشر اليدوي",
|
||||||
"auth_update_failed": "فشل في تحديث معلومات المصادقة"
|
"auth_update_failed": "فشل في تحديث معلومات المصادقة"
|
||||||
|
},
|
||||||
|
"tempmail": {
|
||||||
|
"config_error": "خطأ في ملف التكوين: {error}",
|
||||||
|
"no_email": "لم يتم العثور على بريد إلكتروني للتحقق من المؤشر",
|
||||||
|
"general_error": "حدث خطأ: {error}",
|
||||||
|
"checking_email": "التحقق من البريد الإلكتروني للتحقق من المؤشر ...",
|
||||||
|
"extract_code_failed": "فشل استخراج رمز التحقق: {error}",
|
||||||
|
"configured_email": "البريد الإلكتروني المكون: {البريد الإلكتروني}",
|
||||||
|
"check_email_failed": "فشل التحقق من البريد الإلكتروني: {error}",
|
||||||
|
"no_code": "لا يمكن الحصول على رمز التحقق",
|
||||||
|
"email_found": "تم العثور على البريد الإلكتروني للتحقق من المؤشر",
|
||||||
|
"verification_code": "رمز التحقق: {code}"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -863,5 +863,17 @@
|
|||||||
"auth_update_failed": "Неуспешно актуализиране на информацията за удостоверяване",
|
"auth_update_failed": "Неуспешно актуализиране на информацията за удостоверяване",
|
||||||
"title": "Ръчно удостоверяване на курсора",
|
"title": "Ръчно удостоверяване на курсора",
|
||||||
"updating_database": "Актуализиране на базата данни за удостоверяване на курсора ..."
|
"updating_database": "Актуализиране на базата данни за удостоверяване на курсора ..."
|
||||||
|
},
|
||||||
|
"tempmail": {
|
||||||
|
"no_email": "Не е намерен имейл за проверка на курсора",
|
||||||
|
"config_error": "Грешка в конфигурацията на файла: {грешка}",
|
||||||
|
"general_error": "Възникна грешка: {грешка}",
|
||||||
|
"configured_email": "Конфигуриран имейл: {имейл}",
|
||||||
|
"extract_code_failed": "Кодът за проверка на екстракт не успя: {Грешка}",
|
||||||
|
"checking_email": "Проверка за имейл за проверка на курсора ...",
|
||||||
|
"no_code": "Не можа да получи код за проверка",
|
||||||
|
"email_found": "Намерен имейл за проверка на курсора",
|
||||||
|
"check_email_failed": "Проверете имейла не е успешен: {Грешка}",
|
||||||
|
"verification_code": "Код за проверка: {код}"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -862,5 +862,17 @@
|
|||||||
"description": "Dieses Tool modifiziert die Datei workbench.desktop.main.js, um die Token -Grenze zu umgehen",
|
"description": "Dieses Tool modifiziert die Datei workbench.desktop.main.js, um die Token -Grenze zu umgehen",
|
||||||
"press_enter": "Drücken Sie die Eingabetaste, um fortzufahren ...",
|
"press_enter": "Drücken Sie die Eingabetaste, um fortzufahren ...",
|
||||||
"title": "Bypass Token Limit Tool"
|
"title": "Bypass Token Limit Tool"
|
||||||
|
},
|
||||||
|
"tempmail": {
|
||||||
|
"no_email": "Keine Cursorüberprüfungs -E -Mail gefunden",
|
||||||
|
"general_error": "Es ist ein Fehler aufgetreten: {Fehler}",
|
||||||
|
"config_error": "Konfigurationsdateifehler: {Fehler}",
|
||||||
|
"checking_email": "Überprüfung nach Cursor -Überprüfungs -E -Mail ...",
|
||||||
|
"extract_code_failed": "Verifizierungscode extrahieren fehlgeschlagen: {Fehler}",
|
||||||
|
"configured_email": "Konfigurierte E -Mail: {E -Mail}",
|
||||||
|
"no_code": "Konnte keinen Bestätigungscode erhalten",
|
||||||
|
"check_email_failed": "Überprüfen Sie die E -Mail fehlgeschlagen: {Fehler}",
|
||||||
|
"email_found": "Gefundene Cursor -Überprüfungs -E -Mail gefunden",
|
||||||
|
"verification_code": "Überprüfungscode: {Code}"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -191,6 +191,8 @@
|
|||||||
"setting_password": "Setting Password",
|
"setting_password": "Setting Password",
|
||||||
"manual_code_input": "Manual Code Input",
|
"manual_code_input": "Manual Code Input",
|
||||||
"manual_email_input": "Manual Email Input",
|
"manual_email_input": "Manual Email Input",
|
||||||
|
"suggest_email": "Suggested email: {suggested_email}",
|
||||||
|
"use_suggested_email_or_enter": "Type \"yes\" to use this email or enter your own email:",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"first_name": "First Name",
|
"first_name": "First Name",
|
||||||
"last_name": "Last Name",
|
"last_name": "Last Name",
|
||||||
@ -850,5 +852,17 @@
|
|||||||
"auth_updated_successfully": "Authentication information updated successfully!",
|
"auth_updated_successfully": "Authentication information updated successfully!",
|
||||||
"auth_update_failed": "Failed to update authentication information",
|
"auth_update_failed": "Failed to update authentication information",
|
||||||
"error": "Error: {error}"
|
"error": "Error: {error}"
|
||||||
|
},
|
||||||
|
"tempmail": {
|
||||||
|
"check_email_failed": "Check email failed: {error}",
|
||||||
|
"extract_code_failed": "Extract verification code failed: {error}",
|
||||||
|
"configured_email": "Configured email: {email}",
|
||||||
|
"checking_email": "Checking for Cursor verification email...",
|
||||||
|
"email_found": "Found Cursor verification email",
|
||||||
|
"verification_code": "Verification code: {code}",
|
||||||
|
"no_code": "Could not get verification code",
|
||||||
|
"no_email": "No Cursor verification email found",
|
||||||
|
"config_error": "Config file error: {error}",
|
||||||
|
"general_error": "An error occurred: {error}"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -862,5 +862,17 @@
|
|||||||
"description": "Esta herramienta modifica el archivo workbench.desktop.main.js para evitar el límite del token",
|
"description": "Esta herramienta modifica el archivo workbench.desktop.main.js para evitar el límite del token",
|
||||||
"press_enter": "Presione Entrar para continuar ...",
|
"press_enter": "Presione Entrar para continuar ...",
|
||||||
"title": "Herramienta de límite de token de derivación"
|
"title": "Herramienta de límite de token de derivación"
|
||||||
|
},
|
||||||
|
"tempmail": {
|
||||||
|
"general_error": "Se produjo un error: {error}",
|
||||||
|
"config_error": "Error de archivo de configuración: {error}",
|
||||||
|
"no_email": "No se encuentra el correo electrónico de verificación del cursor",
|
||||||
|
"checking_email": "Comprobación del correo electrónico de verificación del cursor ...",
|
||||||
|
"configured_email": "Correo electrónico configurado: {correo electrónico}",
|
||||||
|
"extract_code_failed": "Extraer el código de verificación fallido: {error}",
|
||||||
|
"no_code": "No pudo obtener el código de verificación",
|
||||||
|
"check_email_failed": "Verifique el correo electrónico fallido: {error}",
|
||||||
|
"email_found": "Correo electrónico de verificación del cursor encontrado",
|
||||||
|
"verification_code": "Código de verificación: {código}"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -862,5 +862,17 @@
|
|||||||
"description": "Cet outil modifie le fichier workbench.desktop.main.js pour contourner la limite de jeton",
|
"description": "Cet outil modifie le fichier workbench.desktop.main.js pour contourner la limite de jeton",
|
||||||
"press_enter": "Appuyez sur Entrée pour continuer ...",
|
"press_enter": "Appuyez sur Entrée pour continuer ...",
|
||||||
"title": "Outil de limite de jeton de contournement"
|
"title": "Outil de limite de jeton de contournement"
|
||||||
|
},
|
||||||
|
"tempmail": {
|
||||||
|
"no_email": "Aucun e-mail de vérification du curseur trouvé",
|
||||||
|
"general_error": "Une erreur s'est produite: {erreur}",
|
||||||
|
"config_error": "Erreur de fichier de configuration: {erreur}",
|
||||||
|
"configured_email": "Email configuré: {e-mail}",
|
||||||
|
"extract_code_failed": "Extraire le code de vérification a échoué: {error}",
|
||||||
|
"checking_email": "Vérification du courrier électronique de vérification du curseur ...",
|
||||||
|
"email_found": "Email de vérification du curseur trouvé",
|
||||||
|
"no_code": "Impossible d'obtenir le code de vérification",
|
||||||
|
"check_email_failed": "Vérifier l'échec de l'e-mail: {Erreur}",
|
||||||
|
"verification_code": "Code de vérification: {code}"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -850,5 +850,17 @@
|
|||||||
"description": "Questo strumento modifica il file workbench.desktop.main.js per bypassare il limite token",
|
"description": "Questo strumento modifica il file workbench.desktop.main.js per bypassare il limite token",
|
||||||
"press_enter": "Premere Invio per continuare ...",
|
"press_enter": "Premere Invio per continuare ...",
|
||||||
"title": "Strumento di limite di bypass token"
|
"title": "Strumento di limite di bypass token"
|
||||||
|
},
|
||||||
|
"tempmail": {
|
||||||
|
"config_error": "Errore del file di configurazione: {errore}",
|
||||||
|
"no_email": "Nessuna e -mail di verifica del cursore trovato",
|
||||||
|
"general_error": "Si è verificato un errore: {errore}",
|
||||||
|
"extract_code_failed": "Extract Verifica Codice non riuscito: {errore}",
|
||||||
|
"configured_email": "Email configurata: {email}",
|
||||||
|
"no_code": "Impossibile ottenere il codice di verifica",
|
||||||
|
"checking_email": "Verificare la verifica della verifica del cursore ...",
|
||||||
|
"check_email_failed": "Controlla l'e -mail non riuscita: {errore}",
|
||||||
|
"email_found": "Email di verifica del cursore trovato",
|
||||||
|
"verification_code": "Codice di verifica: {codice}"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -850,5 +850,17 @@
|
|||||||
"title": "手動カーソル認証",
|
"title": "手動カーソル認証",
|
||||||
"updating_database": "カーソル認証データベースの更新...",
|
"updating_database": "カーソル認証データベースの更新...",
|
||||||
"auth_update_failed": "認証情報の更新に失敗しました"
|
"auth_update_failed": "認証情報の更新に失敗しました"
|
||||||
|
},
|
||||||
|
"tempmail": {
|
||||||
|
"general_error": "エラーが発生しました:{エラー}",
|
||||||
|
"no_email": "カーソル検証メールは見つかりません",
|
||||||
|
"config_error": "構成ファイルエラー:{エラー}",
|
||||||
|
"checking_email": "カーソル検証メールの確認...",
|
||||||
|
"extract_code_failed": "検証コードが失敗した抽出:{エラー}",
|
||||||
|
"configured_email": "構成された電子メール:{電子メール}",
|
||||||
|
"email_found": "カーソル検証メールが見つかりました",
|
||||||
|
"no_code": "確認コードを取得できませんでした",
|
||||||
|
"check_email_failed": "電子メールの失敗を確認する:{エラー}",
|
||||||
|
"verification_code": "検証コード:{code}"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -862,5 +862,17 @@
|
|||||||
"description": "Deze tool wijzigt het bestand Workbench.desktop.main.js om de tokenlimiet te omzeilen",
|
"description": "Deze tool wijzigt het bestand Workbench.desktop.main.js om de tokenlimiet te omzeilen",
|
||||||
"press_enter": "Druk op Enter om door te gaan ...",
|
"press_enter": "Druk op Enter om door te gaan ...",
|
||||||
"title": "Omzeilen token limiet tool"
|
"title": "Omzeilen token limiet tool"
|
||||||
|
},
|
||||||
|
"tempmail": {
|
||||||
|
"no_email": "Geen cursorverificatie -e -mail gevonden",
|
||||||
|
"general_error": "Er is een fout opgetreden: {error}",
|
||||||
|
"config_error": "Config -bestandsfout: {error}",
|
||||||
|
"checking_email": "Controleren op cursorverificatie -e -mail ...",
|
||||||
|
"extract_code_failed": "Extract Verificatiecode mislukt: {error}",
|
||||||
|
"configured_email": "Geconfigureerd e -mail: {e -mail}",
|
||||||
|
"no_code": "Kon geen verificatiecode krijgen",
|
||||||
|
"email_found": "Cursor Verificatie -e -mail gevonden",
|
||||||
|
"check_email_failed": "Controleer e -mail mislukt: {error}",
|
||||||
|
"verification_code": "Verificatiecode: {code}"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -862,5 +862,17 @@
|
|||||||
"description": "Esta ferramenta modifica o arquivo workbench.desktop.main.js para ignorar o limite do token",
|
"description": "Esta ferramenta modifica o arquivo workbench.desktop.main.js para ignorar o limite do token",
|
||||||
"press_enter": "Pressione Enter para continuar ...",
|
"press_enter": "Pressione Enter para continuar ...",
|
||||||
"title": "Ipassue Token Limit Tool"
|
"title": "Ipassue Token Limit Tool"
|
||||||
|
},
|
||||||
|
"tempmail": {
|
||||||
|
"config_error": "Erro de arquivo de configuração: {erro}",
|
||||||
|
"general_error": "Ocorreu um erro: {erro}",
|
||||||
|
"no_email": "Nenhum e -mail de verificação do cursor encontrado",
|
||||||
|
"extract_code_failed": "Código de verificação de extração falhou: {erro}",
|
||||||
|
"checking_email": "Verificando o e -mail de verificação do cursor ...",
|
||||||
|
"configured_email": "Email configurado: {email}",
|
||||||
|
"no_code": "Não foi possível obter o código de verificação",
|
||||||
|
"check_email_failed": "Verifique o e -mail falhado: {erro}",
|
||||||
|
"verification_code": "Código de verificação: {code}",
|
||||||
|
"email_found": "E -mail de verificação do cursor encontrado"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -862,5 +862,17 @@
|
|||||||
"description": "Этот инструмент изменяет файл workbench.desktop.main.js, чтобы обойти предел токена",
|
"description": "Этот инструмент изменяет файл workbench.desktop.main.js, чтобы обойти предел токена",
|
||||||
"press_enter": "Нажмите Enter, чтобы продолжить ...",
|
"press_enter": "Нажмите Enter, чтобы продолжить ...",
|
||||||
"title": "Инструмент ограничения обхода токена"
|
"title": "Инструмент ограничения обхода токена"
|
||||||
|
},
|
||||||
|
"tempmail": {
|
||||||
|
"no_email": "Электронное письмо с проверкой курсора не найдено",
|
||||||
|
"config_error": "Ошибка файла конфигурации: {ошибка}",
|
||||||
|
"extract_code_failed": "Установка кода извлечения проверки: {ошибка}",
|
||||||
|
"general_error": "Произошла ошибка: {ошибка}",
|
||||||
|
"no_code": "Не удалось получить код проверки",
|
||||||
|
"checking_email": "Проверка на проверку курсора по электронной почте ...",
|
||||||
|
"configured_email": "Настройка электронной почты: {электронная почта}",
|
||||||
|
"check_email_failed": "Проверка по электронной почте не удастся: {ошибка}",
|
||||||
|
"verification_code": "Код проверки: {код}",
|
||||||
|
"email_found": "Найдено электронное письмо с проверкой курсора"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -862,5 +862,17 @@
|
|||||||
"description": "Bu araç, jeton sınırını atlamak için workbench.desktop.main.js dosyasını değiştirir",
|
"description": "Bu araç, jeton sınırını atlamak için workbench.desktop.main.js dosyasını değiştirir",
|
||||||
"press_enter": "Devam etmek için Enter tuşuna basın ...",
|
"press_enter": "Devam etmek için Enter tuşuna basın ...",
|
||||||
"title": "Baypas Token Limit Aracı"
|
"title": "Baypas Token Limit Aracı"
|
||||||
|
},
|
||||||
|
"tempmail": {
|
||||||
|
"general_error": "Bir hata oluştu: {hata}",
|
||||||
|
"no_email": "İmleç doğrulama e -postası bulunamadı",
|
||||||
|
"config_error": "Yapılandırma dosya hatası: {error}",
|
||||||
|
"extract_code_failed": "Çıkarma Doğrulama Kodu Başarısız: {Hata}",
|
||||||
|
"configured_email": "Yapılandırılmış e -posta: {e -posta}",
|
||||||
|
"checking_email": "İmleç doğrulama e -postasını kontrol etmek ...",
|
||||||
|
"check_email_failed": "E -postanın başarısız olduğunu kontrol edin: {hata}",
|
||||||
|
"no_code": "Doğrulama kodu alamadı",
|
||||||
|
"email_found": "İmleç doğrulama e -postası bulundu",
|
||||||
|
"verification_code": "Doğrulama kodu: {kod}"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -863,5 +863,17 @@
|
|||||||
"profile": "Hồ sơ {Number}",
|
"profile": "Hồ sơ {Number}",
|
||||||
"profile_list": "Có sẵn {trình duyệt} Hồ sơ:",
|
"profile_list": "Có sẵn {trình duyệt} Hồ sơ:",
|
||||||
"invalid_selection": "Lựa chọn không hợp lệ. Hãy thử lại."
|
"invalid_selection": "Lựa chọn không hợp lệ. Hãy thử lại."
|
||||||
|
},
|
||||||
|
"tempmail": {
|
||||||
|
"config_error": "Lỗi tệp cấu hình: {error}",
|
||||||
|
"general_error": "Đã xảy ra lỗi: {lỗi}",
|
||||||
|
"no_email": "Không tìm thấy email xác minh con trỏ",
|
||||||
|
"checking_email": "Kiểm tra email xác minh con trỏ ...",
|
||||||
|
"configured_email": "Email được định cấu hình: {email}",
|
||||||
|
"extract_code_failed": "Trích xuất mã xác minh không thành công: {error}",
|
||||||
|
"no_code": "Không thể nhận mã xác minh",
|
||||||
|
"check_email_failed": "Kiểm tra email không thành công: {lỗi}",
|
||||||
|
"email_found": "Tìm thấy email xác minh con trỏ",
|
||||||
|
"verification_code": "Mã xác minh: {code}"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -191,6 +191,8 @@
|
|||||||
"setting_password": "设置密码",
|
"setting_password": "设置密码",
|
||||||
"manual_code_input": "手动输入验证码",
|
"manual_code_input": "手动输入验证码",
|
||||||
"manual_email_input": "手动输入邮箱",
|
"manual_email_input": "手动输入邮箱",
|
||||||
|
"suggest_email": "推荐邮箱地址: {suggested_email}",
|
||||||
|
"use_suggested_email_or_enter": "输入\"yes\"使用此邮箱或直接输入您想使用的邮箱地址:",
|
||||||
"password": "密码",
|
"password": "密码",
|
||||||
"first_name": "名字",
|
"first_name": "名字",
|
||||||
"last_name": "姓氏",
|
"last_name": "姓氏",
|
||||||
@ -854,5 +856,17 @@
|
|||||||
"title": "手动Cursor身份验证",
|
"title": "手动Cursor身份验证",
|
||||||
"token_verified": "令牌成功验证了!",
|
"token_verified": "令牌成功验证了!",
|
||||||
"updating_database": "更新Cursor身份验证数据库..."
|
"updating_database": "更新Cursor身份验证数据库..."
|
||||||
|
},
|
||||||
|
"tempmail": {
|
||||||
|
"general_error": "发生错误:{error}",
|
||||||
|
"no_email": "找不到Cursor验证电子邮件",
|
||||||
|
"configured_email": "配置的电子邮件:{email}",
|
||||||
|
"config_error": "配置文件错误:{error}",
|
||||||
|
"extract_code_failed": "提取验证代码失败:{error}",
|
||||||
|
"no_code": "无法获得验证代码",
|
||||||
|
"check_email_failed": "检查电子邮件失败:{error}",
|
||||||
|
"checking_email": "检查Cursor验证电子邮件...",
|
||||||
|
"email_found": "找到Cursor验证电子邮件",
|
||||||
|
"verification_code": "验证代码:{code}"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -188,6 +188,8 @@
|
|||||||
"setting_password": "設置密碼",
|
"setting_password": "設置密碼",
|
||||||
"manual_code_input": "手動輸入驗證碼",
|
"manual_code_input": "手動輸入驗證碼",
|
||||||
"manual_email_input": "手動輸入郵箱地址",
|
"manual_email_input": "手動輸入郵箱地址",
|
||||||
|
"suggest_email": "推薦郵箱地址: {suggested_email}",
|
||||||
|
"use_suggested_email_or_enter": "輸入\"yes\"使用此郵箱或直接輸入您想使用的郵箱地址:",
|
||||||
"password": "密碼",
|
"password": "密碼",
|
||||||
"first_name": "名字",
|
"first_name": "名字",
|
||||||
"last_name": "姓氏",
|
"last_name": "姓氏",
|
||||||
@ -869,5 +871,17 @@
|
|||||||
"title": "手動Cursor身份驗證",
|
"title": "手動Cursor身份驗證",
|
||||||
"updating_database": "更新Cursor身份驗證數據庫...",
|
"updating_database": "更新Cursor身份驗證數據庫...",
|
||||||
"auth_update_failed": "無法更新身份驗證信息"
|
"auth_update_failed": "無法更新身份驗證信息"
|
||||||
|
},
|
||||||
|
"tempmail": {
|
||||||
|
"general_error": "發生錯誤:{error}",
|
||||||
|
"config_error": "配置文件錯誤:{error}",
|
||||||
|
"no_email": "找不到Cursor驗證電子郵件",
|
||||||
|
"checking_email": "檢查Cursor驗證電子郵件...",
|
||||||
|
"extract_code_failed": "提取驗證代碼失敗:{error}",
|
||||||
|
"configured_email": "配置的電子郵件:{email}",
|
||||||
|
"no_code": "無法獲得驗證代碼",
|
||||||
|
"check_email_failed": "檢查電子郵件失敗:{error}",
|
||||||
|
"email_found": "找到Cursor驗證電子郵件",
|
||||||
|
"verification_code": "驗證代碼:{code}"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -116,6 +116,13 @@ def fill_signup_form(page, first_name, last_name, email, config, translator=None
|
|||||||
def get_user_documents_path():
|
def get_user_documents_path():
|
||||||
"""Get user Documents folder path"""
|
"""Get user Documents folder path"""
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
|
try:
|
||||||
|
import winreg
|
||||||
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders") as key:
|
||||||
|
documents_path, _ = winreg.QueryValueEx(key, "Personal")
|
||||||
|
return documents_path
|
||||||
|
except Exception as e:
|
||||||
|
# fallback
|
||||||
return os.path.join(os.path.expanduser("~"), "Documents")
|
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||||
elif sys.platform == "darwin":
|
elif sys.platform == "darwin":
|
||||||
return os.path.join(os.path.expanduser("~"), "Documents")
|
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||||
|
@ -33,6 +33,13 @@ EMOJI = {
|
|||||||
def get_user_documents_path():
|
def get_user_documents_path():
|
||||||
"""Get user Documents folder path"""
|
"""Get user Documents folder path"""
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
|
try:
|
||||||
|
import winreg
|
||||||
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders") as key:
|
||||||
|
documents_path, _ = winreg.QueryValueEx(key, "Personal")
|
||||||
|
return documents_path
|
||||||
|
except Exception as e:
|
||||||
|
# fallback
|
||||||
return os.path.join(os.path.expanduser("~"), "Documents")
|
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||||
elif sys.platform == "darwin":
|
elif sys.platform == "darwin":
|
||||||
return os.path.join(os.path.expanduser("~"), "Documents")
|
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||||
|
@ -125,75 +125,61 @@ function Install-CursorFreeVIP {
|
|||||||
|
|
||||||
Write-Styled "No existing installation file found, starting download..." -Color $Theme.Primary -Prefix "Download"
|
Write-Styled "No existing installation file found, starting download..." -Color $Theme.Primary -Prefix "Download"
|
||||||
|
|
||||||
# Create WebClient and add progress event
|
# Use HttpWebRequest for chunked download with real-time progress bar
|
||||||
$webClient = New-Object System.Net.WebClient
|
$url = $asset.browser_download_url
|
||||||
$webClient.Headers.Add("User-Agent", "PowerShell Script")
|
$outputFile = $downloadPath
|
||||||
|
Write-Styled "Downloading from: $url" -Color $Theme.Info -Prefix "URL"
|
||||||
|
Write-Styled "Saving to: $outputFile" -Color $Theme.Info -Prefix "Path"
|
||||||
|
|
||||||
# Define progress variables
|
$request = [System.Net.HttpWebRequest]::Create($url)
|
||||||
$Global:downloadedBytes = 0
|
$request.UserAgent = "PowerShell Script"
|
||||||
$Global:totalBytes = 0
|
$response = $request.GetResponse()
|
||||||
$Global:lastProgress = 0
|
$totalLength = $response.ContentLength
|
||||||
$Global:lastBytes = 0
|
$responseStream = $response.GetResponseStream()
|
||||||
$Global:lastTime = Get-Date
|
$fileStream = [System.IO.File]::OpenWrite($outputFile)
|
||||||
|
$buffer = New-Object byte[] 8192
|
||||||
# Download progress event
|
$bytesRead = 0
|
||||||
$eventId = [guid]::NewGuid()
|
$totalRead = 0
|
||||||
Register-ObjectEvent -InputObject $webClient -EventName DownloadProgressChanged -Action {
|
$lastProgress = -1
|
||||||
$Global:downloadedBytes = $EventArgs.BytesReceived
|
$startTime = Get-Date
|
||||||
$Global:totalBytes = $EventArgs.TotalBytesToReceive
|
try {
|
||||||
$progress = [math]::Round(($Global:downloadedBytes / $Global:totalBytes) * 100, 1)
|
do {
|
||||||
|
$bytesRead = $responseStream.Read($buffer, 0, $buffer.Length)
|
||||||
# Only update display when progress changes by more than 1%
|
if ($bytesRead -gt 0) {
|
||||||
if ($progress -gt $Global:lastProgress + 1) {
|
$fileStream.Write($buffer, 0, $bytesRead)
|
||||||
$Global:lastProgress = $progress
|
$totalRead += $bytesRead
|
||||||
$downloadedMB = [math]::Round($Global:downloadedBytes / 1MB, 2)
|
$progress = [math]::Round(($totalRead / $totalLength) * 100, 1)
|
||||||
$totalMB = [math]::Round($Global:totalBytes / 1MB, 2)
|
if ($progress -ne $lastProgress) {
|
||||||
|
$elapsed = (Get-Date) - $startTime
|
||||||
# Calculate download speed
|
$speed = if ($elapsed.TotalSeconds -gt 0) { $totalRead / $elapsed.TotalSeconds } else { 0 }
|
||||||
$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) {
|
$speedDisplay = if ($speed -gt 1MB) {
|
||||||
"$([math]::Round($speed / 1MB, 2)) MB/s"
|
"{0:N2} MB/s" -f ($speed / 1MB)
|
||||||
} elseif ($speed -gt 1KB) {
|
} elseif ($speed -gt 1KB) {
|
||||||
"$([math]::Round($speed / 1KB, 2)) KB/s"
|
"{0:N2} KB/s" -f ($speed / 1KB)
|
||||||
} else {
|
} else {
|
||||||
"$([math]::Round($speed, 2)) B/s"
|
"{0:N2} B/s" -f $speed
|
||||||
}
|
}
|
||||||
|
$downloadedMB = [math]::Round($totalRead / 1MB, 2)
|
||||||
Write-Host "`rDownloading: $downloadedMB MB / $totalMB MB ($progress%) - $speedDisplay" -NoNewline -ForegroundColor Cyan
|
$totalMB = [math]::Round($totalLength / 1MB, 2)
|
||||||
|
Write-Progress -Activity "Downloading CursorFreeVIP" -Status "$downloadedMB MB / $totalMB MB ($progress%) - $speedDisplay" -PercentComplete $progress
|
||||||
# Update last data
|
$lastProgress = $progress
|
||||||
$Global:lastBytes = $Global:downloadedBytes
|
|
||||||
$Global:lastTime = $currentTime
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} | Out-Null
|
} while ($bytesRead -gt 0)
|
||||||
|
} finally {
|
||||||
# Download completed event
|
$fileStream.Close()
|
||||||
Register-ObjectEvent -InputObject $webClient -EventName DownloadFileCompleted -Action {
|
$responseStream.Close()
|
||||||
Write-Host "`r" -NoNewline
|
$response.Close()
|
||||||
|
}
|
||||||
|
Write-Progress -Activity "Downloading CursorFreeVIP" -Completed
|
||||||
|
# Check file exists and is not zero size
|
||||||
|
if (!(Test-Path $outputFile) -or ((Get-Item $outputFile).Length -eq 0)) {
|
||||||
|
throw "Download failed or file is empty."
|
||||||
|
}
|
||||||
Write-Styled "Download completed!" -Color $Theme.Success -Prefix "Complete"
|
Write-Styled "Download completed!" -Color $Theme.Success -Prefix "Complete"
|
||||||
Unregister-Event -SourceIdentifier $eventId
|
Write-Styled "File location: $outputFile" -Color $Theme.Info -Prefix "Location"
|
||||||
} | 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 "Starting program..." -Color $Theme.Primary -Prefix "Launch"
|
Write-Styled "Starting program..." -Color $Theme.Primary -Prefix "Launch"
|
||||||
|
Start-Process $outputFile
|
||||||
# Run program
|
|
||||||
Start-Process $downloadPath
|
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
Write-Styled $_.Exception.Message -Color $Theme.Error -Prefix "Error"
|
Write-Styled $_.Exception.Message -Color $Theme.Error -Prefix "Error"
|
||||||
|
@ -32,6 +32,12 @@ EMOJI = {
|
|||||||
def get_user_documents_path():
|
def get_user_documents_path():
|
||||||
"""Get user Documents folder path"""
|
"""Get user Documents folder path"""
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
|
try:
|
||||||
|
import winreg
|
||||||
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders") as key:
|
||||||
|
documents_path, _ = winreg.QueryValueEx(key, "Personal")
|
||||||
|
return documents_path
|
||||||
|
except Exception as e:
|
||||||
return os.path.join(os.path.expanduser("~"), "Documents")
|
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||||
elif sys.platform == "darwin":
|
elif sys.platform == "darwin":
|
||||||
return os.path.join(os.path.expanduser("~"), "Documents")
|
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||||
|
9
utils.py
9
utils.py
@ -6,6 +6,15 @@ import random
|
|||||||
def get_user_documents_path():
|
def get_user_documents_path():
|
||||||
"""Get user documents path"""
|
"""Get user documents path"""
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
|
try:
|
||||||
|
import winreg
|
||||||
|
# 打开注册表
|
||||||
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders") as key:
|
||||||
|
# 获取 "Personal" 键的值,这指向用户的文档目录
|
||||||
|
documents_path, _ = winreg.QueryValueEx(key, "Personal")
|
||||||
|
return documents_path
|
||||||
|
except Exception as e:
|
||||||
|
# fallback
|
||||||
return os.path.expanduser("~\\Documents")
|
return os.path.expanduser("~\\Documents")
|
||||||
else:
|
else:
|
||||||
return os.path.expanduser("~/Documents")
|
return os.path.expanduser("~/Documents")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user