| import readline from 'readline'; |
| import fs from 'fs'; |
| import path from 'path'; |
| import { fileURLToPath } from 'url'; |
|
|
| import { initBrowser, shutdownBrowser, getBrowserContext } from '../browser/browser.js'; |
| import { extractAuthToken } from '../api/chat.js'; |
| import { loadTokens, saveTokens, markValid, removeToken } from '../api/tokenManager.js'; |
| import { loadAuthToken } from '../browser/session.js'; |
|
|
| const __filename = fileURLToPath(import.meta.url); |
| const __dirname = path.dirname(__filename); |
|
|
| function prompt(question) { |
| const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); |
| return new Promise(resolve => rl.question(question, ans => { rl.close(); resolve(ans.trim()); })); |
| } |
|
|
| function ensureAccountDir(id) { |
| const accountDir = path.join(__dirname, '..', '..', 'session', 'accounts', id); |
| if (!fs.existsSync(accountDir)) { |
| fs.mkdirSync(accountDir, { recursive: true }); |
| } |
| return accountDir; |
| } |
|
|
| export async function addAccountInteractive() { |
| console.log('======================================================'); |
| console.log('Добавление нового аккаунта Qwen'); |
| console.log('Браузер откроется, войдите в систему, затем вернитесь к консоли.'); |
| console.log('======================================================'); |
|
|
| const ok = await initBrowser(true, true); |
| if (!ok) { |
| console.error('Не удалось запустить браузер.'); |
| return null; |
| } |
|
|
|
|
|
|
| const ctx = getBrowserContext(); |
| let token = await extractAuthToken(ctx, true); |
|
|
| if (!token) { |
| token = loadAuthToken(); |
| if (token) { |
| console.log('Токен получен из сохранённого файла.'); |
| } |
| } |
|
|
| if (!token) { |
| console.error('Токен не был получен. Аккаунт не добавлен.'); |
| await shutdownBrowser(); |
| return null; |
| } |
|
|
| await shutdownBrowser(); |
| |
|
|
| const id = 'acc_' + Date.now(); |
|
|
|
|
| ensureAccountDir(id); |
| fs.writeFileSync(path.join(__dirname, '..', '..', 'session', 'accounts', id, 'token.txt'), token, 'utf8'); |
|
|
| const list = loadTokens(); |
| list.push({ id, token, resetAt: null }); |
| saveTokens(list); |
|
|
| console.log(`Аккаунт '${id}' добавлен. Всего аккаунтов: ${list.length}`); |
| console.log('======================================================'); |
| return id; |
| } |
|
|
| export async function interactiveAccountMenu() { |
| while (true) { |
| console.log('\n=== Меню управления аккаунтами ==='); |
| console.log('1 - Добавить новый аккаунт'); |
| console.log('2 - Завершить'); |
| const choice = await prompt('Ваш выбор (1/2): '); |
| if (choice === '1') { |
| await addAccountInteractive(); |
| } else if (choice === '2') { |
| break; |
| } else { |
| console.log('Неверный выбор.'); |
| } |
| } |
| } |
|
|
| export async function reloginAccountInteractive() { |
| const tokens = loadTokens(); |
| const invalids = tokens.filter(t => t.invalid); |
| if (!invalids.length) { |
| console.log('Нет аккаунтов, требующих повторного входа.'); |
| await prompt('Нажмите ENTER чтобы вернуться в меню...'); |
| return; |
| } |
|
|
| console.log('\nАккаунты с истекшим токеном:'); |
| invalids.forEach((t, idx) => console.log(`${idx + 1} - ${t.id}`)); |
| const choice = await prompt('Выберите номер аккаунта для повторного входа: '); |
| const num = parseInt(choice, 10); |
| if (isNaN(num) || num < 1 || num > invalids.length) { |
| console.log('Неверный выбор.'); |
| return; |
| } |
| const account = invalids[num - 1]; |
|
|
| console.log(`\nПовторная авторизация для ${account.id}`); |
| const ok = await initBrowser(true, true); |
| if (!ok) { |
| console.error('Не удалось запустить браузер.'); |
| return; |
| } |
|
|
| const token = await extractAuthToken(getBrowserContext(), true); |
| await shutdownBrowser(); |
|
|
| if (!token) { |
| console.error('Не удалось извлечь токен.'); |
| return; |
| } |
|
|
| |
| markValid(account.id, token); |
| fs.writeFileSync(path.join(__dirname, '..', '..', 'session', 'accounts', account.id, 'token.txt'), token, 'utf8'); |
|
|
| console.log(`Токен обновлён для ${account.id}`); |
| } |
|
|
| export async function removeAccountInteractive() { |
| const tokens = loadTokens(); |
| if (!tokens.length) { |
| console.log('Нет сохранённых аккаунтов.'); |
| await prompt('ENTER чтобы вернуться...'); |
| return; |
| } |
|
|
| console.log('\nДоступные аккаунты:'); |
| tokens.forEach((t, idx) => console.log(`${idx + 1} - ${t.id}`)); |
| const choice = await prompt('Номер аккаунта, который нужно удалить (или ENTER для отмены): '); |
| if (!choice) return; |
| const num = parseInt(choice, 10); |
| if (isNaN(num) || num < 1 || num > tokens.length) { |
| console.log('Неверный выбор.'); |
| await prompt('ENTER чтобы вернуться...'); |
| return; |
| } |
| const acc = tokens[num - 1]; |
| const confirm = await prompt(`Точно удалить ${acc.id}? (y/N): `); |
| if (confirm.toLowerCase() !== 'y') return; |
|
|
| removeToken(acc.id); |
|
|
| |
| const dir = path.join(__dirname, '..', '..', 'session', 'accounts', acc.id); |
| if (fs.existsSync(dir)) { |
| fs.rmSync(dir, { recursive: true, force: true }); |
| } |
|
|
| console.log(`Аккаунт ${acc.id} удалён.`); |
| await prompt('ENTER чтобы вернуться...'); |
| } |