Update youProvider.mjs
This commit is contained in:
+277
-179
@@ -1,19 +1,18 @@
|
|||||||
import {EventEmitter} from "events";
|
import {EventEmitter} from "events";
|
||||||
import {connect} from "puppeteer-real-browser";
|
|
||||||
import {v4 as uuidV4} from "uuid";
|
import {v4 as uuidV4} from "uuid";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import {fileURLToPath} from "url";
|
import {fileURLToPath} from "url";
|
||||||
import {createDirectoryIfNotExists, createDocx, extractCookie, getSessionCookie, sleep} from "../utils.mjs";
|
import {createDocx, extractCookie, getSessionCookie, sleep} from "../utils.mjs";
|
||||||
import {exec} from 'child_process';
|
import {exec} from 'child_process';
|
||||||
import '../proxyAgent.mjs';
|
import '../proxyAgent.mjs';
|
||||||
import {formatMessages} from '../formatMessages.mjs';
|
import {formatMessages} from '../formatMessages.mjs';
|
||||||
import NetworkMonitor from '../networkMonitor.mjs';
|
import NetworkMonitor from '../networkMonitor.mjs';
|
||||||
import {detectBrowser} from '../utils/browserDetector.mjs';
|
|
||||||
import {insertGarbledText} from './garbledText.mjs';
|
import {insertGarbledText} from './garbledText.mjs';
|
||||||
import * as imageStorage from "../imageStorage.mjs";
|
import * as imageStorage from "../imageStorage.mjs";
|
||||||
import Logger from './logger.mjs';
|
import Logger from './logger.mjs';
|
||||||
import {clientState} from "../index.mjs";
|
import {clientState} from "../index.mjs";
|
||||||
|
import SessionManager from '../sessionManager.mjs';
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
@@ -22,11 +21,11 @@ class YouProvider {
|
|||||||
constructor(config) {
|
constructor(config) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.sessions = {};
|
this.sessions = {};
|
||||||
// 可以是 'chrome', 'edge', 或 'auto'
|
this.isCustomModeEnabled = process.env.USE_CUSTOM_MODE === "true"; // 是否启用自定义模式
|
||||||
this.preferredBrowser = 'auto';
|
this.isRotationEnabled = process.env.ENABLE_MODE_ROTATION === "true"; // 是否启用模式轮换
|
||||||
this.isCustomModeEnabled = process.env.USE_CUSTOM_MODE === "true";
|
this.uploadFileFormat = process.env.UPLOAD_FILE_FORMAT || 'docx'; // 上传文件格式
|
||||||
this.isRotationEnabled = process.env.ENABLE_MODE_ROTATION === "true";
|
this.enableRequestLimit = process.env.ENABLE_REQUEST_LIMIT === 'true'; // 是否启用请求次数限制
|
||||||
this.uploadFileFormat = process.env.UPLOAD_FILE_FORMAT || 'docx';
|
this.requestLimit = parseInt(process.env.REQUEST_LIMIT, 10) || 3; // 请求次数上限
|
||||||
this.networkMonitor = new NetworkMonitor();
|
this.networkMonitor = new NetworkMonitor();
|
||||||
this.logger = new Logger();
|
this.logger = new Logger();
|
||||||
}
|
}
|
||||||
@@ -64,47 +63,22 @@ class YouProvider {
|
|||||||
async init(config) {
|
async init(config) {
|
||||||
console.log(`本项目依赖Chrome或Edge浏览器,请勿关闭弹出的浏览器窗口。如果出现错误请检查是否已安装Chrome或Edge浏览器。`);
|
console.log(`本项目依赖Chrome或Edge浏览器,请勿关闭弹出的浏览器窗口。如果出现错误请检查是否已安装Chrome或Edge浏览器。`);
|
||||||
|
|
||||||
// 检测Chrome和Edge浏览器
|
|
||||||
const browserPath = detectBrowser(this.preferredBrowser);
|
|
||||||
this.sessions = {};
|
|
||||||
const timeout = 120000;
|
const timeout = 120000;
|
||||||
// 创建共享浏览器用户数据
|
|
||||||
const sharedProfilePath = path.join(__dirname, "browser_profiles", "shared_profile");
|
|
||||||
createDirectoryIfNotExists(sharedProfilePath);
|
|
||||||
// 创建浏览器
|
|
||||||
const response = await connect({
|
|
||||||
headless: "auto",
|
|
||||||
turnstile: true,
|
|
||||||
customConfig: {
|
|
||||||
userDataDir: sharedProfilePath,
|
|
||||||
executablePath: browserPath,
|
|
||||||
args: [
|
|
||||||
'--no-sandbox',
|
|
||||||
'--disable-setuid-sandbox',
|
|
||||||
'--remote-debugging-address=::',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const {page, browser} = response;
|
|
||||||
this.browser = browser;
|
|
||||||
this.page = page;
|
|
||||||
|
|
||||||
this.skipAccountValidation = process.env.SKIP_ACCOUNT_VALIDATION !== "true";
|
this.skipAccountValidation = process.env.SKIP_ACCOUNT_VALIDATION !== "true";
|
||||||
|
|
||||||
if (process.env.USE_MANUAL_LOGIN === "true") {
|
this.sessionManager = new SessionManager(this);
|
||||||
this.sessions['manual_login'] = {
|
await this.sessionManager.initBrowserInstancesInBatch();
|
||||||
configIndex: 0,
|
|
||||||
valid: false,
|
|
||||||
};
|
|
||||||
console.log("当前使用手动登录模式,跳过config.mjs文件中的 cookie 验证");
|
|
||||||
|
|
||||||
|
if (process.env.USE_MANUAL_LOGIN === "true") {
|
||||||
|
console.log("当前使用手动登录模式,跳过config.mjs文件中的 cookie 验证");
|
||||||
|
// 获取一个浏览器实例
|
||||||
|
const browserInstance = this.sessionManager.browserInstances[0];
|
||||||
|
const page = browserInstance.page;
|
||||||
// 手动登录
|
// 手动登录
|
||||||
console.log(`请在打开的浏览器窗口中手动登录 You.com`);
|
console.log(`请在打开的浏览器窗口中手动登录 You.com`);
|
||||||
await page.goto("https://you.com", {timeout: timeout});
|
await page.goto("https://you.com", {timeout: timeout});
|
||||||
await sleep(3000); // 等待页面加载完毕
|
await sleep(3000); // 等待页面加载完毕
|
||||||
|
|
||||||
// 等待手动登录完成
|
|
||||||
const {loginInfo, sessionCookie} = await this.waitForManualLogin(page);
|
const {loginInfo, sessionCookie} = await this.waitForManualLogin(page);
|
||||||
if (sessionCookie) {
|
if (sessionCookie) {
|
||||||
const email = loginInfo || sessionCookie.email || 'manual_login';
|
const email = loginInfo || sessionCookie.email || 'manual_login';
|
||||||
@@ -123,9 +97,10 @@ class YouProvider {
|
|||||||
|
|
||||||
// 设置隐身模式 cookie
|
// 设置隐身模式 cookie
|
||||||
await page.setCookie(...sessionCookie);
|
await page.setCookie(...sessionCookie);
|
||||||
|
this.sessionManager.setSessions(this.sessions);
|
||||||
} else {
|
} else {
|
||||||
console.error(`未能获取有效的登录 cookie`);
|
console.error(`未能获取有效的登录 cookie`);
|
||||||
await browser.close();
|
await browserInstance.browser.close();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 使用配置文件中的 cookie
|
// 使用配置文件中的 cookie
|
||||||
@@ -181,102 +156,18 @@ class YouProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(`已添加 ${Object.keys(this.sessions).length} 个 cookie`);
|
console.log(`已添加 ${Object.keys(this.sessions).length} 个 cookie`);
|
||||||
|
this.sessionManager.setSessions(this.sessions);
|
||||||
}
|
}
|
||||||
|
const validSessionsCount = Object.keys(this.sessions).filter(username => this.sessions[username].valid).length;
|
||||||
|
this.isSingleSession = (validSessionsCount === 1) || (process.env.USE_MANUAL_LOGIN === "true");
|
||||||
if (this.skipAccountValidation) {
|
if (this.skipAccountValidation) {
|
||||||
console.log(`开始验证cookie有效性...`);
|
console.log(`开始验证cookie有效性...`);
|
||||||
for (const originalUsername of Object.keys(this.sessions)) {
|
// 获取浏览器实例列表
|
||||||
let currentUsername = originalUsername;
|
const browserInstances = this.sessionManager.browserInstances;
|
||||||
let session = this.sessions[currentUsername];
|
// 创建一个账号队列
|
||||||
|
const accountQueue = [...Object.keys(this.sessions)];
|
||||||
try {
|
// 并发验证账号
|
||||||
// 设置账户的Cookie
|
await this.validateAccounts(browserInstances, accountQueue);
|
||||||
await page.setCookie(...getSessionCookie(
|
|
||||||
session.jwtSession,
|
|
||||||
session.jwtToken,
|
|
||||||
session.ds,
|
|
||||||
session.dsr
|
|
||||||
));
|
|
||||||
await page.goto("https://you.com", {timeout: timeout});
|
|
||||||
await sleep(5000); // 等待加载完毕
|
|
||||||
|
|
||||||
// 检测是否为 team 账号
|
|
||||||
session.isTeamAccount = await page.evaluate(() => {
|
|
||||||
let teamElement = document.querySelector('div._15zm0ko1 p._15zm0ko2');
|
|
||||||
if (teamElement && teamElement.textContent.trim() === 'Your Team') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let altTeamElement = document.querySelector('div.sc-1a751f3b-0.hyfnxg');
|
|
||||||
return altTeamElement && altTeamElement.textContent.includes('Team');
|
|
||||||
});
|
|
||||||
|
|
||||||
// 如果遇到盾了就多等一段时间
|
|
||||||
const pageContent = await page.content();
|
|
||||||
if (pageContent.indexOf("https://challenges.cloudflare.com") > -1) {
|
|
||||||
console.log(`请在30秒内完成人机验证 (${currentUsername})`);
|
|
||||||
await page.evaluate(() => {
|
|
||||||
alert("请在30秒内完成人机验证");
|
|
||||||
});
|
|
||||||
await sleep(30000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证 cookie 有效性
|
|
||||||
try {
|
|
||||||
const content = await page.evaluate(() => {
|
|
||||||
return fetch("https://you.com/api/user/getYouProState").then((res) => res.text());
|
|
||||||
});
|
|
||||||
const json = JSON.parse(content);
|
|
||||||
const allowNonPro = process.env.ALLOW_NON_PRO === "true";
|
|
||||||
|
|
||||||
if (session.isTeamAccount) {
|
|
||||||
console.log(`${currentUsername} 有效 (Team 计划)`);
|
|
||||||
session.valid = true;
|
|
||||||
session.isTeam = true;
|
|
||||||
|
|
||||||
// 获取 Team 订阅信息
|
|
||||||
const teamSubscriptionInfo = await this.getTeamSubscriptionInfo(json.org_subscriptions[0]);
|
|
||||||
if (teamSubscriptionInfo) {
|
|
||||||
session.subscriptionInfo = teamSubscriptionInfo;
|
|
||||||
}
|
|
||||||
} else if (json.subscriptions && json.subscriptions.length > 0) {
|
|
||||||
console.log(`${currentUsername} 有效 (Pro 计划)`);
|
|
||||||
session.valid = true;
|
|
||||||
session.isPro = true;
|
|
||||||
|
|
||||||
// 获取 Pro 订阅信息
|
|
||||||
const subscriptionInfo = await this.getSubscriptionInfo(page);
|
|
||||||
if (subscriptionInfo) {
|
|
||||||
session.subscriptionInfo = subscriptionInfo;
|
|
||||||
}
|
|
||||||
} else if (allowNonPro) {
|
|
||||||
console.log(`${currentUsername} 有效 (非Pro)`);
|
|
||||||
console.warn(`警告: ${currentUsername} 没有Pro或Team订阅,功能受限。`);
|
|
||||||
session.valid = true;
|
|
||||||
session.isPro = false;
|
|
||||||
session.isTeam = false;
|
|
||||||
} else {
|
|
||||||
console.log(`${currentUsername} 无有效订阅`);
|
|
||||||
console.warn(`警告: ${currentUsername} 可能没有有效的订阅。请检查You是否有有效的Pro或Team订阅。`);
|
|
||||||
await this.clearYouCookies(page);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log(`${currentUsername} 已失效`);
|
|
||||||
console.warn(`警告: ${currentUsername} 验证失败。请检查cookie是否有效。`);
|
|
||||||
console.error(e);
|
|
||||||
await this.clearYouCookies(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentUsername !== Object.keys(this.sessions)[Object.keys(this.sessions).length - 1]) {
|
|
||||||
await this.clearYouCookies(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`验证账户 ${currentUsername} 时出错:`, e);
|
|
||||||
session.valid = false;
|
|
||||||
await this.clearYouCookies(page);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("订阅信息汇总:");
|
console.log("订阅信息汇总:");
|
||||||
for (const [username, session] of Object.entries(this.sessions)) {
|
for (const [username, session] of Object.entries(this.sessions)) {
|
||||||
if (session.valid) {
|
if (session.valid) {
|
||||||
@@ -307,15 +198,175 @@ class YouProvider {
|
|||||||
this.sessions[username].valid = true;
|
this.sessions[username].valid = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开始网络监控
|
// 开始网络监控
|
||||||
await this.networkMonitor.startMonitoring();
|
await this.networkMonitor.startMonitoring();
|
||||||
const validSessionsCount = Object.keys(this.sessions).filter(username => this.sessions[username].valid).length;
|
|
||||||
this.isSingleSession = (validSessionsCount === 1) || (process.env.USE_MANUAL_LOGIN === "true");
|
|
||||||
console.log(`验证完毕,有效cookie数量 ${validSessionsCount}`);
|
console.log(`验证完毕,有效cookie数量 ${validSessionsCount}`);
|
||||||
console.log(`开启 ${this.isSingleSession ? "单账号模式" : "多账号模式"}`);
|
console.log(`开启 ${this.isSingleSession ? "单账号模式" : "多账号模式"}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async validateAccounts(browserInstances, accountQueue) {
|
||||||
|
const timeout = 120000; // 毫秒
|
||||||
|
|
||||||
|
// 自定义并发上限
|
||||||
|
const desiredConcurrencyLimit = 16;
|
||||||
|
|
||||||
|
// 实际浏览器实例数量
|
||||||
|
const browserCount = browserInstances.length;
|
||||||
|
|
||||||
|
// 最终生效的并发总量 = min(浏览器实例数量, 自定义并发上限)
|
||||||
|
const effectiveConcurrency = Math.min(browserCount, desiredConcurrencyLimit);
|
||||||
|
|
||||||
|
// 如果 Cookie 数量 < 浏览器实例数,则复制到至少 browserCount
|
||||||
|
if (accountQueue.length < browserCount) {
|
||||||
|
const originalQueue = [...accountQueue];
|
||||||
|
if (originalQueue.length === 0) {
|
||||||
|
console.warn("无法验证:accountQueue 为空,未提供任何 Cookie。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (accountQueue.length < browserCount) {
|
||||||
|
const randomIndex = Math.floor(Math.random() * originalQueue.length);
|
||||||
|
accountQueue.push(originalQueue[randomIndex]);
|
||||||
|
}
|
||||||
|
console.log(`队列已扩充到至少与浏览器实例数相同:${accountQueue.length} 条`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果时队列比“有效并发”小,则再复制到至少 effectiveConcurrency
|
||||||
|
if (accountQueue.length < effectiveConcurrency) {
|
||||||
|
const originalQueue2 = [...accountQueue];
|
||||||
|
while (accountQueue.length < effectiveConcurrency && originalQueue2.length > 0) {
|
||||||
|
const randomIndex = Math.floor(Math.random() * originalQueue2.length);
|
||||||
|
accountQueue.push(originalQueue2[randomIndex]);
|
||||||
|
}
|
||||||
|
console.log(`队列已扩充到至少并发数:${accountQueue.length} 条 (并发=${effectiveConcurrency})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当前正在执行的 任务
|
||||||
|
const validationPromises = [];
|
||||||
|
|
||||||
|
// 轮询
|
||||||
|
let browserIndex = 0;
|
||||||
|
function getNextBrowserInstance() {
|
||||||
|
const instance = browserInstances[browserIndex];
|
||||||
|
browserIndex = (browserIndex + 1) % browserCount;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (accountQueue.length > 0) {
|
||||||
|
// 如果当前正在执行的任务数量 >= 有效并发
|
||||||
|
if (validationPromises.length >= effectiveConcurrency) {
|
||||||
|
await Promise.race(validationPromises);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从队列头拿出一个账号
|
||||||
|
const currentUsername = accountQueue.shift();
|
||||||
|
|
||||||
|
const browserInstance = getNextBrowserInstance();
|
||||||
|
const page = browserInstance.page;
|
||||||
|
const session = this.sessions[currentUsername];
|
||||||
|
|
||||||
|
const validationTask = (async () => {
|
||||||
|
try {
|
||||||
|
await page.setCookie(...getSessionCookie(
|
||||||
|
session.jwtSession,
|
||||||
|
session.jwtToken,
|
||||||
|
session.ds,
|
||||||
|
session.dsr
|
||||||
|
));
|
||||||
|
|
||||||
|
await page.goto("https://you.com", { timeout });
|
||||||
|
|
||||||
|
await sleep(5000);
|
||||||
|
|
||||||
|
// 检测是否为 team 账号
|
||||||
|
session.isTeamAccount = await page.evaluate(() => {
|
||||||
|
let teamElement = document.querySelector('div._15zm0ko1 p._15zm0ko2');
|
||||||
|
if (teamElement && teamElement.textContent.trim() === 'Your Team') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let altTeamElement = document.querySelector('div.sc-1a751f3b-0.hyfnxg');
|
||||||
|
return altTeamElement && altTeamElement.textContent.includes('Team');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 如果遇到盾了就多等一段时间
|
||||||
|
const pageContent = await page.content();
|
||||||
|
if (pageContent.includes("https://challenges.cloudflare.com")) {
|
||||||
|
console.log(`请在30秒内完成人机验证 (${currentUsername})`);
|
||||||
|
await page.evaluate(() => {
|
||||||
|
alert("请在30秒内完成人机验证");
|
||||||
|
});
|
||||||
|
await sleep(30000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证 cookie 有效性
|
||||||
|
try {
|
||||||
|
const content = await page.evaluate(() => {
|
||||||
|
return fetch("https://you.com/api/user/getYouProState").then(res => res.text());
|
||||||
|
});
|
||||||
|
const json = JSON.parse(content);
|
||||||
|
const allowNonPro = process.env.ALLOW_NON_PRO === "true";
|
||||||
|
|
||||||
|
if (session.isTeamAccount) {
|
||||||
|
console.log(`${currentUsername} 校验成功 -> Team 账号`);
|
||||||
|
session.valid = true;
|
||||||
|
session.isTeam = true;
|
||||||
|
|
||||||
|
// 获取 Team 订阅信息
|
||||||
|
const teamSubscriptionInfo = await this.getTeamSubscriptionInfo(json.org_subscriptions?.[0]);
|
||||||
|
if (teamSubscriptionInfo) {
|
||||||
|
session.subscriptionInfo = teamSubscriptionInfo;
|
||||||
|
}
|
||||||
|
} else if (Array.isArray(json.subscriptions) && json.subscriptions.length > 0) {
|
||||||
|
console.log(`${currentUsername} 校验成功 -> Pro 账号`);
|
||||||
|
session.valid = true;
|
||||||
|
session.isPro = true;
|
||||||
|
|
||||||
|
// 获取 Pro 订阅信息
|
||||||
|
const subscriptionInfo = await this.getSubscriptionInfo(page);
|
||||||
|
if (subscriptionInfo) {
|
||||||
|
session.subscriptionInfo = subscriptionInfo;
|
||||||
|
}
|
||||||
|
} else if (allowNonPro) {
|
||||||
|
console.log(`${currentUsername} 有效 (非Pro)`);
|
||||||
|
console.warn(`警告: ${currentUsername} 没有Pro或Team订阅,功能受限。`);
|
||||||
|
session.valid = true;
|
||||||
|
session.isPro = false;
|
||||||
|
session.isTeam = false;
|
||||||
|
} else {
|
||||||
|
console.log(`${currentUsername} 无有效订阅`);
|
||||||
|
console.warn(`警告: ${currentUsername} 可能没有有效的订阅。请检查You是否有有效的Pro或Team订阅。`);
|
||||||
|
session.valid = false;
|
||||||
|
}
|
||||||
|
} catch (parseErr) {
|
||||||
|
console.log(`${currentUsername} 已失效`);
|
||||||
|
console.warn(`警告: ${currentUsername} 验证失败。请检查cookie是否有效。`);
|
||||||
|
console.error(parseErr);
|
||||||
|
session.valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是多账号模式
|
||||||
|
if (!this.isSingleSession) {
|
||||||
|
await this.clearYouCookies(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (errorVisit) {
|
||||||
|
console.error(`验证账户 ${currentUsername} 时出错:`, errorVisit);
|
||||||
|
session.valid = false;
|
||||||
|
await this.clearYouCookies(page);
|
||||||
|
} finally {
|
||||||
|
const index = validationPromises.indexOf(validationTask);
|
||||||
|
if (index > -1) {
|
||||||
|
validationPromises.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
validationPromises.push(validationTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待所有任务完成
|
||||||
|
await Promise.all(validationPromises);
|
||||||
|
}
|
||||||
|
|
||||||
async getTeamSubscriptionInfo(subscription) {
|
async getTeamSubscriptionInfo(subscription) {
|
||||||
if (!subscription) {
|
if (!subscription) {
|
||||||
console.warn('没有有效的Team订阅信息');
|
console.warn('没有有效的Team订阅信息');
|
||||||
@@ -448,14 +499,16 @@ class YouProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async clearYouCookies(page) {
|
async clearYouCookies(page) {
|
||||||
const client = await page.target().createCDPSession();
|
if (!page.isClosed()) {
|
||||||
await client.send('Network.clearBrowserCookies');
|
const client = await page.target().createCDPSession();
|
||||||
await client.send('Network.clearBrowserCache');
|
await client.send('Network.clearBrowserCookies');
|
||||||
const cookies = await page.cookies('https://you.com');
|
await client.send('Network.clearBrowserCache');
|
||||||
for (const cookie of cookies) {
|
const cookies = await page.cookies('https://you.com');
|
||||||
await page.deleteCookie(cookie);
|
for (const cookie of cookies) {
|
||||||
|
await page.deleteCookie(cookie);
|
||||||
|
}
|
||||||
|
console.log('已自动清理 cookie');
|
||||||
}
|
}
|
||||||
console.log('已自动清理 cookie');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForManualLogin(page) {
|
async waitForManualLogin(page) {
|
||||||
@@ -605,7 +658,15 @@ class YouProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCompletion({username, messages, stream = false, proxyModel, useCustomMode = false, modeSwitched = false}) {
|
async getCompletion({
|
||||||
|
username,
|
||||||
|
messages,
|
||||||
|
browserInstance,
|
||||||
|
stream = false,
|
||||||
|
proxyModel,
|
||||||
|
useCustomMode = false,
|
||||||
|
modeSwitched = false
|
||||||
|
}) {
|
||||||
if (this.networkMonitor.isNetworkBlocked()) {
|
if (this.networkMonitor.isNetworkBlocked()) {
|
||||||
throw new Error("网络异常,请稍后再试");
|
throw new Error("网络异常,请稍后再试");
|
||||||
}
|
}
|
||||||
@@ -614,9 +675,7 @@ class YouProvider {
|
|||||||
throw new Error(`用户 ${username} 的会话无效`);
|
throw new Error(`用户 ${username} 的会话无效`);
|
||||||
}
|
}
|
||||||
const emitter = new EventEmitter();
|
const emitter = new EventEmitter();
|
||||||
let page = this.page;
|
let page = browserInstance.page;
|
||||||
let browser = this.browser;
|
|
||||||
|
|
||||||
// 初始化 session 相关的模式属性
|
// 初始化 session 相关的模式属性
|
||||||
if (session.currentMode === undefined) {
|
if (session.currentMode === undefined) {
|
||||||
session.currentMode = this.isCustomModeEnabled ? 'custom' : 'default';
|
session.currentMode = this.isCustomModeEnabled ? 'custom' : 'default';
|
||||||
@@ -625,8 +684,8 @@ class YouProvider {
|
|||||||
session.requestsInCurrentMode = 0;
|
session.requestsInCurrentMode = 0;
|
||||||
session.lastDefaultThreshold = 0;
|
session.lastDefaultThreshold = 0;
|
||||||
session.switchThreshold = this.getRandomSwitchThreshold(session);
|
session.switchThreshold = this.getRandomSwitchThreshold(session);
|
||||||
|
session.youTotalRequests = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.isSingleSession) {
|
if (!this.isSingleSession) {
|
||||||
// 设置账号Cookie
|
// 设置账号Cookie
|
||||||
await page.setCookie(...getSessionCookie(
|
await page.setCookie(...getSessionCookie(
|
||||||
@@ -742,24 +801,20 @@ class YouProvider {
|
|||||||
// 检查该session是否已经创建对应模型的对应user chat mode
|
// 检查该session是否已经创建对应模型的对应user chat mode
|
||||||
let userChatModeId = "custom";
|
let userChatModeId = "custom";
|
||||||
if (effectiveUseCustomMode) {
|
if (effectiveUseCustomMode) {
|
||||||
if (!this.config.sessions[session.configIndex].user_chat_mode_id) {
|
if (!this.config.user_chat_mode_id) {
|
||||||
this.config.sessions[session.configIndex].user_chat_mode_id = {};
|
this.config.user_chat_mode_id = {};
|
||||||
}
|
}
|
||||||
|
// 检查与当前用户名匹配记录
|
||||||
// 检查是否存在与当前用户名匹配的记录
|
if (!this.config.user_chat_mode_id[username]) {
|
||||||
let existingUserRecord = Object.keys(this.config.sessions[session.configIndex].user_chat_mode_id).find(key => key === username);
|
// 为当前用户创建新记录
|
||||||
|
this.config.user_chat_mode_id[username] = {};
|
||||||
if (!existingUserRecord) {
|
|
||||||
// 为当前用户创建新的记录
|
|
||||||
this.config.sessions[session.configIndex].user_chat_mode_id[username] = {};
|
|
||||||
// 写回config
|
|
||||||
fs.writeFileSync("./config.mjs", "export const config = " + JSON.stringify(this.config, null, 4));
|
fs.writeFileSync("./config.mjs", "export const config = " + JSON.stringify(this.config, null, 4));
|
||||||
console.log(`Created new record for user: ${username}`);
|
console.log(`Created new record for user: ${username}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否存在对应模型的记录
|
// 检查是否存在对应模型记录
|
||||||
if (!this.config.sessions[session.configIndex].user_chat_mode_id[username][proxyModel]) {
|
if (!this.config.user_chat_mode_id[username][proxyModel]) {
|
||||||
// 创建新的user chat mode
|
// 创建新的 user chat mode
|
||||||
let userChatMode = await page.evaluate(
|
let userChatMode = await page.evaluate(
|
||||||
async (proxyModel, proxyModelName) => {
|
async (proxyModel, proxyModelName) => {
|
||||||
return fetch("https://you.com/api/custom_assistants/assistants", {
|
return fetch("https://you.com/api/custom_assistants/assistants", {
|
||||||
@@ -785,8 +840,8 @@ class YouProvider {
|
|||||||
uuidV4().substring(0, 4)
|
uuidV4().substring(0, 4)
|
||||||
);
|
);
|
||||||
if (userChatMode.chat_mode_id) {
|
if (userChatMode.chat_mode_id) {
|
||||||
this.config.sessions[session.configIndex].user_chat_mode_id[username][proxyModel] = userChatMode.chat_mode_id;
|
this.config.user_chat_mode_id[username][proxyModel] = userChatMode.chat_mode_id;
|
||||||
// 写回config
|
// 写回 config
|
||||||
fs.writeFileSync("./config.mjs", "export const config = " + JSON.stringify(this.config, null, 4));
|
fs.writeFileSync("./config.mjs", "export const config = " + JSON.stringify(this.config, null, 4));
|
||||||
console.log(`Created new chat mode for user ${username} and model ${proxyModel}`);
|
console.log(`Created new chat mode for user ${username} and model ${proxyModel}`);
|
||||||
} else {
|
} else {
|
||||||
@@ -794,7 +849,7 @@ class YouProvider {
|
|||||||
console.log("Failed to create user chat mode, will use default mode instead.");
|
console.log("Failed to create user chat mode, will use default mode instead.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
userChatModeId = this.config.sessions[session.configIndex].user_chat_mode_id[username][proxyModel];
|
userChatModeId = this.config.user_chat_mode_id[username][proxyModel];
|
||||||
} else {
|
} else {
|
||||||
console.log("Custom mode is disabled, using default mode.");
|
console.log("Custom mode is disabled, using default mode.");
|
||||||
}
|
}
|
||||||
@@ -811,7 +866,15 @@ class YouProvider {
|
|||||||
const formattedMessages = formatMessages(messages, proxyModel, randomFileName);
|
const formattedMessages = formatMessages(messages, proxyModel, randomFileName);
|
||||||
|
|
||||||
// 将格式化后的消息转换为纯文本
|
// 将格式化后的消息转换为纯文本
|
||||||
let previousMessages = formattedMessages.map((msg) => `${msg.role}: ${msg.content}`).join("\n\n");
|
let previousMessages = formattedMessages
|
||||||
|
.map((msg) => {
|
||||||
|
if (!msg.role) {
|
||||||
|
return msg.content; // role为空只返回content
|
||||||
|
} else {
|
||||||
|
return `${msg.role}: ${msg.content}`;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.join("\n\n");
|
||||||
|
|
||||||
// 插入乱码(如果启用)
|
// 插入乱码(如果启用)
|
||||||
previousMessages = insertGarbledText(previousMessages);
|
previousMessages = insertGarbledText(previousMessages);
|
||||||
@@ -995,13 +1058,20 @@ class YouProvider {
|
|||||||
if (!this.isSingleSession) {
|
if (!this.isSingleSession) {
|
||||||
await this.clearYouCookies(page);
|
await this.clearYouCookies(page);
|
||||||
}
|
}
|
||||||
|
// 检查请求次数是否达到上限
|
||||||
|
if (this.enableRequestLimit && session.youTotalRequests >= this.requestLimit) {
|
||||||
|
session.modeStatus.default = false;
|
||||||
|
session.modeStatus.custom = false;
|
||||||
|
this.sessionManager.recordLimitedAccount(username);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 缓存
|
// 缓存
|
||||||
let buffer = '';
|
let buffer = '';
|
||||||
let heartbeatInterval = null; // 心跳计时器
|
let heartbeatInterval = null; // 心跳计时器
|
||||||
let errorTimer = null; // 错误计时器
|
let errorTimer = null; // 错误计时器
|
||||||
const ERROR_TIMEOUT = 15000;
|
let errorCount = 0; // 错误计数器
|
||||||
|
const ERROR_TIMEOUT = 15000; // 错误计时器超时时间
|
||||||
const self = this;
|
const self = this;
|
||||||
page.exposeFunction("callback" + traceId, async (event, data) => {
|
page.exposeFunction("callback" + traceId, async (event, data) => {
|
||||||
if (isEnding) return;
|
if (isEnding) return;
|
||||||
@@ -1125,19 +1195,23 @@ class YouProvider {
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "error": {
|
case "error": {
|
||||||
if (isEnding) return; // 如果已经结束,则忽略错误
|
if (isEnding) return; // 已结束则忽略
|
||||||
|
|
||||||
console.error("请求发生错误", data);
|
console.error("请求发生错误", data);
|
||||||
if (errorTimer) {
|
errorCount++;
|
||||||
clearTimeout(errorTimer);
|
if (errorCount >= 3) {
|
||||||
}
|
|
||||||
errorTimer = setTimeout(async () => {
|
|
||||||
console.log("连接超时,终止请求");
|
|
||||||
const errorMessage = "连接中断,未收到服务器响应";
|
const errorMessage = "连接中断,未收到服务器响应";
|
||||||
emitter.emit("completion", traceId, errorMessage);
|
if (errorTimer) {
|
||||||
finalResponse += ` (${errorMessage})`;
|
clearTimeout(errorTimer);
|
||||||
|
errorTimer = null;
|
||||||
|
}
|
||||||
isEnding = true;
|
isEnding = true;
|
||||||
|
finalResponse += ` (${errorMessage})`;
|
||||||
await cleanup();
|
await cleanup();
|
||||||
|
emitter.emit("completion", traceId, errorMessage);
|
||||||
emitter.emit("end", traceId);
|
emitter.emit("end", traceId);
|
||||||
|
|
||||||
|
// 记录日志
|
||||||
self.logger.logRequest({
|
self.logger.logRequest({
|
||||||
email: username,
|
email: username,
|
||||||
time: requestTime,
|
time: requestTime,
|
||||||
@@ -1146,13 +1220,36 @@ class YouProvider {
|
|||||||
completed: false,
|
completed: false,
|
||||||
unusualQueryVolume: unusualQueryVolumeTriggered,
|
unusualQueryVolume: unusualQueryVolumeTriggered,
|
||||||
});
|
});
|
||||||
}, ERROR_TIMEOUT);
|
} else {
|
||||||
|
if (errorTimer) {
|
||||||
|
clearTimeout(errorTimer);
|
||||||
|
}
|
||||||
|
errorTimer = setTimeout(async () => {
|
||||||
|
console.log("连接超时,终止请求");
|
||||||
|
const errorMessage = "连接中断,未收到服务器响应";
|
||||||
|
|
||||||
|
emitter.emit("completion", traceId, errorMessage);
|
||||||
|
finalResponse += ` (${errorMessage})`;
|
||||||
|
|
||||||
|
isEnding = true;
|
||||||
|
await cleanup();
|
||||||
|
|
||||||
|
emitter.emit("end", traceId);
|
||||||
|
self.logger.logRequest({
|
||||||
|
email: username,
|
||||||
|
time: requestTime,
|
||||||
|
mode: session.currentMode,
|
||||||
|
model: proxyModel,
|
||||||
|
completed: false,
|
||||||
|
unusualQueryVolume: unusualQueryVolumeTriggered,
|
||||||
|
});
|
||||||
|
}, ERROR_TIMEOUT);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// proxy response
|
// proxy response
|
||||||
const req_param = new URLSearchParams();
|
const req_param = new URLSearchParams();
|
||||||
req_param.append("page", "1");
|
req_param.append("page", "1");
|
||||||
@@ -1357,8 +1454,8 @@ class YouProvider {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重新发送请求
|
|
||||||
const responseTimeoutTimer = proxyModel === "openai_o1" || proxyModel === "openai_o1_preview" ? 120000 : 60000;
|
const responseTimeoutTimer = proxyModel === "openai_o1" || proxyModel === "openai_o1_preview" ? 120000 : 60000;
|
||||||
|
|
||||||
// 重新发送请求
|
// 重新发送请求
|
||||||
async function resendPreviousRequest() {
|
async function resendPreviousRequest() {
|
||||||
try {
|
try {
|
||||||
@@ -1373,7 +1470,6 @@ class YouProvider {
|
|||||||
responseAfter20Seconds = '';
|
responseAfter20Seconds = '';
|
||||||
buffer = '';
|
buffer = '';
|
||||||
customEndMarkerEnabled = false;
|
customEndMarkerEnabled = false;
|
||||||
|
|
||||||
clearTimeout(responseTimeout);
|
clearTimeout(responseTimeout);
|
||||||
|
|
||||||
responseTimeout = setTimeout(async () => {
|
responseTimeout = setTimeout(async () => {
|
||||||
@@ -1465,8 +1561,10 @@ class YouProvider {
|
|||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始执行 setupEventSource
|
// 初始执行 setupEventSource
|
||||||
await setupEventSource(page, url, traceId, customEndMarker);
|
await setupEventSource(page, url, traceId, customEndMarker);
|
||||||
|
session.youTotalRequests = (session.youTotalRequests || 0) + 1; // 增加请求次数
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("评估过程中出错:", error);
|
console.error("评估过程中出错:", error);
|
||||||
|
|||||||
Reference in New Issue
Block a user