This commit is contained in:
hkyc
2025-03-31 09:55:54 +08:00
parent 4ef08d7775
commit 4759813f6e
32 changed files with 3879 additions and 0 deletions

561
menu.py Normal file
View File

@@ -0,0 +1,561 @@
import asyncio
import sys
import os
from datetime import datetime
from typing import Dict, Any, List, Callable, Awaitable
from loguru import logger
# 导入功能模块
import upload_accounts
import reset_extracted
import reupload_all
try:
import retry_failed
has_retry_failed = True
except ImportError:
has_retry_failed = False
try:
import reset_retrying
has_reset_retrying = True
except ImportError:
has_reset_retrying = False
try:
import delete_db
has_delete_db = True
except ImportError:
has_delete_db = False
from core.config import Config
from core.logger import setup_logger
from core.database import DatabaseManager
class MenuSystem:
def __init__(self):
self.config = Config.from_yaml()
self.logger = setup_logger(self.config)
self.db_manager = DatabaseManager(self.config)
# 定义菜单项
self.menu_items = [
{
"key": "1",
"title": "重新上传所有账号",
"description": "重置所有账号的提取状态并重新上传到API服务器推荐",
"handler": self.reupload_all_menu
},
{
"key": "2",
"title": "上传账号到API",
"description": "将注册成功的账号上传到API服务器",
"handler": self.upload_accounts_menu
},
{
"key": "3",
"title": "重置账号提取状态",
"description": "将账号的extracted字段重置为0允许重新上传",
"handler": self.reset_extracted_menu
}
]
# 添加可选功能
if has_retry_failed:
self.menu_items.append({
"key": "4",
"title": "重试失败账号",
"description": "重新尝试注册失败的账号",
"handler": self.retry_failed_menu
})
if has_reset_retrying:
self.menu_items.append({
"key": "5",
"title": "重置正在重试的账号",
"description": "将状态为retrying的账号重置为failed",
"handler": self.reset_retrying_menu
})
if has_delete_db:
self.menu_items.append({
"key": "6",
"title": "删除数据库记录",
"description": "根据条件删除数据库中的记录",
"handler": self.delete_db_menu
})
# 添加退出选项
self.menu_items.append({
"key": "q",
"title": "退出程序",
"description": "退出菜单系统",
"handler": self.exit_menu
})
async def initialize(self):
"""初始化数据库连接"""
await self.db_manager.initialize()
async def cleanup(self):
"""清理资源"""
await self.db_manager.cleanup()
async def show_menu(self):
"""显示主菜单"""
os.system('cls' if os.name == 'nt' else 'clear')
print("\n===== Cursor 账号管理系统 =====\n")
# 显示菜单项
for item in self.menu_items:
print(f"{item['key']}. {item['title']} - {item['description']}")
print("\n请选择功能 (输入对应数字或q退出):", end=" ")
choice = input().strip().lower()
# 查找选择的菜单项
selected_item = next((item for item in self.menu_items if item["key"] == choice), None)
if selected_item:
await selected_item["handler"]()
else:
print("\n无效的选择,请重试!")
input("按Enter键继续...")
await self.show_menu()
async def upload_accounts_menu(self):
"""上传账号菜单"""
os.system('cls' if os.name == 'nt' else 'clear')
print("\n===== 上传账号到API =====\n")
# 统计账号状态
resetter = reset_extracted.ExtractedResetter()
await resetter.initialize()
stats = await resetter.count_success_accounts()
await resetter.cleanup()
print(f"当前状态: 总成功账号: {stats['total']}, 已提取: {stats['extracted']}, 未提取: {stats['not_extracted']}")
if stats['not_extracted'] == 0:
print("\n没有待上传的账号。是否要重置所有账号的提取状态?(y/n)", end=" ")
reset_choice = input().strip().lower()
if reset_choice == 'y':
await self.reset_all_extracted()
print("\n已重置所有账号的提取状态,现在可以上传。")
else:
print("\n未重置状态,无法上传账号。")
input("\n按Enter键返回主菜单...")
return
print("\n选项:")
print("1. 预览待上传账号 (dry-run)")
print("2. 上传所有账号")
print("3. 上传指定批次数量")
print("4. 修改批次大小 (默认: 100)")
print("5. 禁用代理")
print("b. 返回主菜单")
choice = input("\n请选择操作: ").strip().lower()
args = []
use_proxy = True
batch_size = 100
max_batches = 0
if choice == "1":
args = ["--dry-run"]
elif choice == "2":
args = [] # 使用默认设置上传所有
elif choice == "3":
try:
batches = int(input("请输入要处理的批次数量: ").strip())
if batches > 0:
args = [f"--batches", f"{batches}"]
max_batches = batches
else:
print("批次数量必须大于0")
input("按Enter键继续...")
await self.upload_accounts_menu()
return
except ValueError:
print("无效的输入,必须是整数")
input("按Enter键继续...")
await self.upload_accounts_menu()
return
elif choice == "4":
try:
size = int(input("请输入批次大小: ").strip())
if size > 0:
batch_size = size
args = [f"--batch-size", f"{size}"]
else:
print("批次大小必须大于0")
input("按Enter键继续...")
await self.upload_accounts_menu()
return
except ValueError:
print("无效的输入,必须是整数")
input("按Enter键继续...")
await self.upload_accounts_menu()
return
elif choice == "5":
use_proxy = False
args = ["--no-proxy"]
elif choice == "b":
await self.show_menu()
return
else:
print("无效的选择,请重试!")
input("按Enter键继续...")
await self.upload_accounts_menu()
return
# 处理输入的批次大小和批次数量组合
if choice == "3" and choice == "4":
args = [f"--batches", f"{max_batches}", f"--batch-size", f"{batch_size}"]
# 添加代理设置
if not use_proxy and "--no-proxy" not in args:
args.append("--no-proxy")
print(f"\n准备执行命令: python upload_accounts.py {' '.join(args)}")
print("按Enter键开始执行或按Ctrl+C取消...")
input()
# 存储原始sys.argv并替换
original_argv = sys.argv.copy()
sys.argv = [sys.argv[0]] + args
try:
# 执行上传账号功能
await upload_accounts.main()
except Exception as e:
self.logger.error(f"执行上传账号出错: {e}")
finally:
# 恢复sys.argv
sys.argv = original_argv
input("\n操作完成按Enter键返回主菜单...")
await self.show_menu()
async def reset_extracted_menu(self):
"""重置提取状态菜单"""
os.system('cls' if os.name == 'nt' else 'clear')
print("\n===== 重置账号提取状态 =====\n")
# 统计账号状态
resetter = reset_extracted.ExtractedResetter()
await resetter.initialize()
stats = await resetter.count_success_accounts()
print(f"当前状态: 总成功账号: {stats['total']}, 已提取: {stats['extracted']}, 未提取: {stats['not_extracted']}")
print("\n选项:")
print("1. 预览账号状态 (dry-run)")
print("2. 重置所有账号的提取状态")
print("3. 重置指定模式的账号提取状态")
print("b. 返回主菜单")
choice = input("\n请选择操作: ").strip().lower()
args = []
if choice == "1":
args = ["--dry-run"]
elif choice == "2":
print("\n确定要重置所有账号的提取状态吗?这将允许已提取的账号再次上传。(y/n)", end=" ")
confirm = input().strip().lower()
if confirm != 'y':
print("操作已取消")
input("按Enter键继续...")
await self.reset_extracted_menu()
return
elif choice == "3":
pattern = input("请输入邮箱匹配模式 (例如: outlook.com): ").strip()
if pattern:
args = ["--pattern", pattern]
else:
print("模式不能为空")
input("按Enter键继续...")
await self.reset_extracted_menu()
return
elif choice == "b":
await self.show_menu()
return
else:
print("无效的选择,请重试!")
input("按Enter键继续...")
await self.reset_extracted_menu()
return
# 执行重置
print(f"\n准备执行命令: python reset_extracted.py {' '.join(args)}")
print("按Enter键开始执行或按Ctrl+C取消...")
input()
# 存储原始sys.argv并替换
original_argv = sys.argv.copy()
sys.argv = [sys.argv[0]] + args
try:
# 执行重置操作
await reset_extracted.main()
except Exception as e:
self.logger.error(f"执行重置提取状态出错: {e}")
finally:
# 恢复sys.argv
sys.argv = original_argv
await resetter.cleanup()
input("\n操作完成按Enter键返回主菜单...")
await self.show_menu()
async def reupload_all_menu(self):
"""重新上传所有账号菜单"""
os.system('cls' if os.name == 'nt' else 'clear')
print("\n===== 重新上传所有账号 =====\n")
print("此操作将:")
print("1. 重置所有成功账号的提取状态")
print("2. 重新上传所有账号到API服务器")
print("\n警告: 此操作可能需要较长时间,请确保网络连接稳定。")
print("是否继续? (y/n)", end=" ")
choice = input().strip().lower()
if choice != 'y':
print("\n操作已取消")
input("\n按Enter键返回主菜单...")
await self.show_menu()
return
try:
# 执行重新上传
await reupload_all.main()
except Exception as e:
self.logger.error(f"重新上传过程中出错: {e}")
finally:
input("\n操作完成按Enter键返回主菜单...")
await self.show_menu()
async def retry_failed_menu(self):
"""重试失败账号菜单"""
if not has_retry_failed:
print("\n功能不可用: retry_failed.py 未找到")
input("按Enter键返回主菜单...")
await self.show_menu()
return
os.system('cls' if os.name == 'nt' else 'clear')
print("\n===== 重试失败账号 =====\n")
print("此功能将重新尝试注册失败的账号。")
# 这里可以添加更多的统计信息显示
print("\n选项:")
print("1. 执行账号重试")
print("b. 返回主菜单")
choice = input("\n请选择操作: ").strip().lower()
if choice == "1":
# 执行重试失败账号功能
print("\n准备重试失败账号...")
print("按Enter键开始执行或按Ctrl+C取消...")
input()
# 存储原始sys.argv
original_argv = sys.argv.copy()
sys.argv = [sys.argv[0]]
try:
# 执行重试功能
await retry_failed.main()
except Exception as e:
self.logger.error(f"执行重试失败账号出错: {e}")
finally:
# 恢复sys.argv
sys.argv = original_argv
elif choice == "b":
await self.show_menu()
return
else:
print("无效的选择,请重试!")
input("按Enter键继续...")
await self.retry_failed_menu()
return
input("\n操作完成按Enter键返回主菜单...")
await self.show_menu()
async def reset_retrying_menu(self):
"""重置正在重试的账号菜单"""
if not has_reset_retrying:
print("\n功能不可用: reset_retrying.py 未找到")
input("按Enter键返回主菜单...")
await self.show_menu()
return
os.system('cls' if os.name == 'nt' else 'clear')
print("\n===== 重置正在重试的账号 =====\n")
print("此功能将状态为retrying的账号重置为failed。")
# 这里可以添加更多的统计信息显示
print("\n选项:")
print("1. 执行重置retrying状态")
print("b. 返回主菜单")
choice = input("\n请选择操作: ").strip().lower()
if choice == "1":
# 执行重置retrying状态功能
print("\n准备重置正在重试的账号...")
print("按Enter键开始执行或按Ctrl+C取消...")
input()
# 存储原始sys.argv
original_argv = sys.argv.copy()
sys.argv = [sys.argv[0]]
try:
# 执行重置功能
await reset_retrying.main()
except Exception as e:
self.logger.error(f"执行重置retrying状态出错: {e}")
finally:
# 恢复sys.argv
sys.argv = original_argv
elif choice == "b":
await self.show_menu()
return
else:
print("无效的选择,请重试!")
input("按Enter键继续...")
await self.reset_retrying_menu()
return
input("\n操作完成按Enter键返回主菜单...")
await self.show_menu()
async def delete_db_menu(self):
"""删除数据库记录菜单"""
if not has_delete_db:
print("\n功能不可用: delete_db.py 未找到")
input("按Enter键返回主菜单...")
await self.show_menu()
return
os.system('cls' if os.name == 'nt' else 'clear')
print("\n===== 删除数据库记录 =====\n")
print("此功能将根据条件删除数据库中的记录。")
print("警告: 删除操作不可恢复,请谨慎操作!")
print("\n选项:")
print("1. 交互式删除(按状态)")
print("2. 删除所有记录")
print("b. 返回主菜单")
choice = input("\n请选择操作: ").strip().lower()
if choice == "b":
await self.show_menu()
return
elif choice == "2":
print("\n警告: 此操作将删除数据库中的所有记录!")
print("确定要继续吗?(y/n)", end=" ")
confirm = input().strip().lower()
if confirm != 'y':
print("操作已取消")
input("按Enter键继续...")
await self.delete_db_menu()
return
# 执行全部删除
args = ["--all", "--confirm"]
print(f"\n准备执行命令: python delete_db.py {' '.join(args)}")
print("按Enter键开始执行或按Ctrl+C取消...")
input()
# 存储原始sys.argv
original_argv = sys.argv.copy()
sys.argv = [sys.argv[0]] + args
try:
# 执行删除功能
await delete_db.main()
except Exception as e:
self.logger.error(f"执行删除数据库记录出错: {e}")
finally:
# 恢复sys.argv
sys.argv = original_argv
input("\n操作完成按Enter键返回主菜单...")
await self.show_menu()
return
elif choice == "1":
# 执行交互式删除
args = ["--interactive"]
print(f"\n准备执行命令: python delete_db.py {' '.join(args)}")
print("按Enter键开始执行或按Ctrl+C取消...")
input()
# 存储原始sys.argv
original_argv = sys.argv.copy()
sys.argv = [sys.argv[0]] + args
try:
# 执行删除功能
await delete_db.main()
except Exception as e:
self.logger.error(f"执行删除数据库记录出错: {e}")
finally:
# 恢复sys.argv
sys.argv = original_argv
input("\n操作完成按Enter键返回主菜单...")
await self.show_menu()
return
else:
print("无效的选择,请重试!")
input("按Enter键继续...")
await self.delete_db_menu()
return
async def reset_all_extracted(self):
"""重置所有账号的提取状态"""
resetter = reset_extracted.ExtractedResetter()
await resetter.initialize()
try:
await resetter.reset_extracted()
finally:
await resetter.cleanup()
async def exit_menu(self):
"""退出菜单"""
print("\n感谢使用,再见!")
sys.exit(0)
async def main():
menu = MenuSystem()
try:
await menu.initialize()
await menu.show_menu()
except KeyboardInterrupt:
print("\n程序被用户中断")
except Exception as e:
logger.error(f"程序执行出错: {e}")
finally:
await menu.cleanup()
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\n程序被用户中断")
except Exception as e:
print(f"程序崩溃: {e}")