diff --git a/batch-start.js b/batch-start.js new file mode 100644 index 0000000..e7764d9 --- /dev/null +++ b/batch-start.js @@ -0,0 +1,29 @@ +#!/usr/bin/env node +/** + * 批量注册启动脚本 + */ + +require('dotenv').config(); +const BatchRegister = require('./src/tools/account-register/batch-register'); + +// 配置你的3个 AdsPower Profile ID +const PROFILES = [ + 'k172d58u', + 'k172d4mb', + 'k1728p8l' +]; + +// 启动批量注册 +const batch = new BatchRegister({ + profiles: PROFILES, // 3个profile + concurrency: 1, // 并发3个 + maxCount: Infinity, // 无限循环 + delayBetweenRuns: 10000, // 批次间隔10秒 + maxRetries: 3, // 单次失败重试3次 + retryDelay: 30000 // 重试间隔30秒 +}); + +batch.start().catch(error => { + console.error('批量注册异常:', error); + process.exit(1); +}); diff --git a/src/tools/account-register/batch-register.js b/src/tools/account-register/batch-register.js new file mode 100644 index 0000000..ff2580a --- /dev/null +++ b/src/tools/account-register/batch-register.js @@ -0,0 +1,206 @@ +/** + * Batch Register - 批量自动注册(支持并发) + */ + +const logger = require('../../shared/logger'); +const WindsurfRegister = require('./sites/windsurf'); + +class BatchRegister { + constructor(options = {}) { + // AdsPower profile配置 + this.profiles = options.profiles || [process.env.ADSPOWER_USER_ID]; + this.concurrency = Math.min(options.concurrency || 1, this.profiles.length); + + // 执行配置 + this.maxCount = options.maxCount || Infinity; + this.delayBetweenRuns = options.delayBetweenRuns || 10000; + this.maxRetries = options.maxRetries || 3; + this.retryDelay = options.retryDelay || 30000; + + // 统计数据 + this.stats = { + total: 0, + success: 0, + failed: 0, + running: 0, + startTime: null + }; + + this.running = false; + } + + /** + * 执行单次注册(带重试) + */ + async runOnce(profileId, taskId) { + let retryCount = 0; + + while (retryCount < this.maxRetries) { + try { + logger.info('BatchRegister', `\n${'='.repeat(60)}`); + logger.info('BatchRegister', `[任务${taskId}] 使用Profile: ${profileId}`); + logger.info('BatchRegister', `[任务${taskId}] 第 ${this.stats.total + 1} 次注册 (重试: ${retryCount}/${this.maxRetries})`); + logger.info('BatchRegister', `${'='.repeat(60)}\n`); + + this.stats.running++; + + const register = new WindsurfRegister({ adspowerUserId: profileId }); + const result = await register.register(); + + this.stats.running--; + + if (result.success) { + this.stats.success++; + logger.success('BatchRegister', `[任务${taskId}] ✓ 注册成功!邮箱: ${result.account.email}`); + return true; + } + + } catch (error) { + this.stats.running--; + retryCount++; + logger.error('BatchRegister', `[任务${taskId}] 注册失败: ${error.message}`); + + if (retryCount < this.maxRetries) { + logger.warn('BatchRegister', `[任务${taskId}] ${this.retryDelay/1000}秒后进行第 ${retryCount + 1} 次重试...`); + await this.delay(this.retryDelay); + } + } + } + + // 所有重试都失败 + this.stats.failed++; + logger.error('BatchRegister', `[任务${taskId}] ✗ 注册失败,已达最大重试次数 (${this.maxRetries})`); + return false; + } + + /** + * 延迟函数 + */ + async delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + /** + * 格式化时长 + */ + formatDuration(ms) { + const seconds = Math.floor(ms / 1000); + const minutes = Math.floor(seconds / 60); + const hours = Math.floor(minutes / 60); + + if (hours > 0) { + return `${hours}小时${minutes % 60}分钟`; + } else if (minutes > 0) { + return `${minutes}分钟${seconds % 60}秒`; + } else { + return `${seconds}秒`; + } + } + + /** + * 打印统计信息 + */ + printStats() { + const duration = Date.now() - this.stats.startTime; + const successRate = this.stats.total > 0 + ? ((this.stats.success / this.stats.total) * 100).toFixed(2) + : 0; + + logger.info('BatchRegister', '\n' + '='.repeat(60)); + logger.info('BatchRegister', '📊 批量注册统计'); + logger.info('BatchRegister', '='.repeat(60)); + logger.info('BatchRegister', `⏱️ 运行时长: ${this.formatDuration(duration)}`); + logger.info('BatchRegister', `🔄 并发数: ${this.concurrency} (Profiles: ${this.profiles.length}个)`); + logger.info('BatchRegister', `🏃 运行中: ${this.stats.running}`); + logger.info('BatchRegister', `📈 总次数: ${this.stats.total}`); + logger.info('BatchRegister', `✅ 成功: ${this.stats.success} (${successRate}%)`); + logger.info('BatchRegister', `❌ 失败: ${this.stats.failed}`); + logger.info('BatchRegister', `⚡ 平均耗时: ${this.stats.total > 0 ? this.formatDuration(duration / this.stats.total) : '0秒'}`); + logger.info('BatchRegister', '='.repeat(60) + '\n'); + } + + /** + * 启动批量注册(并发版本) + */ + async start() { + this.running = true; + this.stats.startTime = Date.now(); + + logger.info('BatchRegister', '\n🚀 批量注册启动'); + logger.info('BatchRegister', `目标次数: ${this.maxCount === Infinity ? '无限' : this.maxCount}`); + logger.info('BatchRegister', `并发数: ${this.concurrency}`); + logger.info('BatchRegister', `Profiles: ${this.profiles.join(', ')}`); + logger.info('BatchRegister', `注册间隔: ${this.delayBetweenRuns/1000}秒`); + logger.info('BatchRegister', `单次重试: ${this.maxRetries}次\n`); + + // 捕获 Ctrl+C + process.on('SIGINT', async () => { + logger.warn('BatchRegister', '\n\n⚠️ 收到停止信号,等待当前任务完成...'); + this.running = false; + }); + + // 并发控制:使用 profile 池 + const tasks = []; + let profileIndex = 0; + + while (this.running && this.stats.total < this.maxCount) { + // 如果当前运行任务数 < 并发数,启动新任务 + while (tasks.length < this.concurrency && this.stats.total < this.maxCount && this.running) { + this.stats.total++; + const taskId = this.stats.total; + const profileId = this.profiles[profileIndex % this.profiles.length]; + profileIndex++; + + const task = this.runOnce(profileId, taskId).then((success) => { + // 任务完成后,从任务列表中移除 + const index = tasks.indexOf(task); + if (index > -1) { + tasks.splice(index, 1); + } + return success; + }); + + tasks.push(task); + + // 短暂延迟,避免同时启动 + await this.delay(1000); + } + + // 等待至少一个任务完成 + if (tasks.length > 0) { + await Promise.race(tasks); + } + + // 定期打印统计(每完成5次) + if (this.stats.total % 5 === 0 && tasks.length === 0) { + this.printStats(); + } + + // 任务间隔 + if (tasks.length === 0 && this.running && this.stats.total < this.maxCount) { + logger.info('BatchRegister', `⏳ 等待 ${this.delayBetweenRuns/1000} 秒后继续...\n`); + await this.delay(this.delayBetweenRuns); + } + } + + // 等待所有剩余任务完成 + if (tasks.length > 0) { + logger.info('BatchRegister', `等待 ${tasks.length} 个任务完成...`); + await Promise.all(tasks); + } + + // 结束统计 + this.printStats(); + logger.success('BatchRegister', '🎉 批量注册完成!'); + } + + /** + * 停止批量注册 + */ + stop() { + this.running = false; + logger.warn('BatchRegister', '⚠️ 正在停止批量注册...'); + } +} + +module.exports = BatchRegister; diff --git a/src/tools/account-register/sites/windsurf.js b/src/tools/account-register/sites/windsurf.js index f23be5d..0cbe561 100644 --- a/src/tools/account-register/sites/windsurf.js +++ b/src/tools/account-register/sites/windsurf.js @@ -20,7 +20,7 @@ const CardGenerator = require('../../card-generator/generator'); const database = require('../../database'); class WindsurfRegister { - constructor() { + constructor(options = {}) { this.siteName = 'Windsurf'; this.siteUrl = 'https://windsurf.com/account/register'; this.dataGen = new AccountDataGenerator(); @@ -31,6 +31,9 @@ class WindsurfRegister { this.currentStep = 0; this.accountData = null; + // AdsPower配置(支持多profile并发) + this.adspowerUserId = options.adspowerUserId || process.env.ADSPOWER_USER_ID; + // 记录注册时间和额外信息 this.registrationTime = null; this.quotaInfo = null; @@ -194,12 +197,12 @@ class WindsurfRegister { logger.info(this.siteName, '启动 AdsPower 指纹浏览器...'); // 检查 AdsPower 配置 - const adspowerUserId = process.env.ADSPOWER_USER_ID; + const adspowerUserId = this.adspowerUserId; if (!adspowerUserId) { logger.error(this.siteName, ''); logger.error(this.siteName, '❌ 未配置 ADSPOWER_USER_ID'); logger.error(this.siteName, ''); - logger.error(this.siteName, '请在 .env 文件中配置:'); + logger.error(this.siteName, '请在 .env 文件中配置或传入 options.adspowerUserId:'); logger.error(this.siteName, 'ADSPOWER_USER_ID=your_profile_id'); logger.error(this.siteName, ''); throw new Error('未配置 AdsPower 用户ID');