qwenproxy-cli 1.6.10 → 1.6.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/clean-cache.js +390 -30
- package/dist/delete-chats.js +946 -445
- package/dist/index.js +612 -100
- package/dist/login.js +417 -51
- package/dist/reset-cooldowns.js +769 -407
- package/dist/sync-clients.js +4 -1
- package/package.json +2 -2
- package/src/api/server.ts +8 -4
- package/src/core/config.ts +4 -1
- package/src/core/model-alias.ts +1 -0
- package/src/core/version.ts +1 -1
- package/src/core/watchdog.ts +4 -3
- package/src/routes/chat/account.ts +12 -0
- package/src/routes/chat/streaming.ts +18 -2
- package/src/services/auth-playwright.ts +3 -2
- package/src/services/captcha-coordinator.ts +41 -11
- package/src/services/captcha-solver.ts +400 -2
- package/src/services/chat-cleanup.ts +11 -2
- package/src/services/playwright.ts +135 -50
- package/src/services/qwen-chat-pool.ts +52 -9
- package/src/services/qwen-headers.ts +18 -1
- package/src/services/qwen.ts +35 -7
- package/src/services/session-keeper.ts +70 -8
package/dist/clean-cache.js
CHANGED
|
@@ -997,7 +997,7 @@ var init_config = __esm({
|
|
|
997
997
|
// Version header on Qwen API requests = the deployed web bundle version
|
|
998
998
|
// (fallback when dynamic DOM detection is not yet completed).
|
|
999
999
|
// Override via env when Qwen ships a new bundle.
|
|
1000
|
-
QWEN_WEB_VERSION: z.string().default("0.3.
|
|
1000
|
+
QWEN_WEB_VERSION: z.string().default("0.3.43"),
|
|
1001
1001
|
// Controls bx-ua/bx-umidtoken injection on the GENERAL API paths
|
|
1002
1002
|
// (chats/new, settings): those work without them (live-probed). The
|
|
1003
1003
|
// completions path is the exception — the 0.2.86 HAR shows the real
|
|
@@ -1040,6 +1040,7 @@ var init_config = __esm({
|
|
|
1040
1040
|
CAPTCHA_SOLVER_ENABLED: z.string().default("true"),
|
|
1041
1041
|
CAPTCHA_SOLVER_MAX_ATTEMPTS: z.string().default("3"),
|
|
1042
1042
|
CAPTCHA_SOLVER_TIMEOUT_MS: z.string().default("15000"),
|
|
1043
|
+
CAPTCHA_SLIDER_TIMEOUT_MS: z.string().default("8000"),
|
|
1043
1044
|
CAPTCHA_SOLVER_RETRY_DELAY_MS: z.string().default("1000"),
|
|
1044
1045
|
CAPTCHA_SOLVER_SETTLE_MS: z.string().default("2000"),
|
|
1045
1046
|
CAPTCHA_ACCOUNT_COOLDOWN_MS: z.string().default("120000"),
|
|
@@ -1191,6 +1192,8 @@ var init_config = __esm({
|
|
|
1191
1192
|
enabled: env.CAPTCHA_SOLVER_ENABLED === "true",
|
|
1192
1193
|
maxAttempts: Math.max(1, Math.min(5, parseInt(env.CAPTCHA_SOLVER_MAX_ATTEMPTS))),
|
|
1193
1194
|
timeoutMs: Math.max(0, parseInt(env.CAPTCHA_SOLVER_TIMEOUT_MS)),
|
|
1195
|
+
/** Max wait for a challenge slider to become visible (slow WAF renders). */
|
|
1196
|
+
sliderTimeoutMs: Math.max(500, parseInt(env.CAPTCHA_SLIDER_TIMEOUT_MS)),
|
|
1194
1197
|
retryDelayMs: Math.max(0, parseInt(env.CAPTCHA_SOLVER_RETRY_DELAY_MS)),
|
|
1195
1198
|
settleMs: Math.max(0, parseInt(env.CAPTCHA_SOLVER_SETTLE_MS)),
|
|
1196
1199
|
/** Rest an account whose challenge could not be cleared before reusing it. */
|
|
@@ -2035,6 +2038,26 @@ function clearAccountCooldown(accountId) {
|
|
|
2035
2038
|
}
|
|
2036
2039
|
}
|
|
2037
2040
|
}
|
|
2041
|
+
function getAccountCooldownInfo(accountId) {
|
|
2042
|
+
const entry = cooldowns.get(accountId);
|
|
2043
|
+
if (!entry) return null;
|
|
2044
|
+
const remaining = entry.until - Date.now();
|
|
2045
|
+
if (remaining <= 0) {
|
|
2046
|
+
cooldowns.delete(accountId);
|
|
2047
|
+
if (accountId !== "global") {
|
|
2048
|
+
try {
|
|
2049
|
+
updateAccountCooldown(accountId, 0, null);
|
|
2050
|
+
} catch (err) {
|
|
2051
|
+
console.error(
|
|
2052
|
+
`\u274C [AccountManager] Failed to clear expired cooldown in DB:`,
|
|
2053
|
+
err.message
|
|
2054
|
+
);
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
return null;
|
|
2058
|
+
}
|
|
2059
|
+
return { onCooldown: true, remainingMs: remaining, reason: entry.reason };
|
|
2060
|
+
}
|
|
2038
2061
|
function markAccountHeadersReady(accountId) {
|
|
2039
2062
|
if (!accountId || accountId === "global") return;
|
|
2040
2063
|
headersReadyAccounts.add(accountId);
|
|
@@ -2348,6 +2371,294 @@ function logBaxiaCaptcha(event, fields = {}, important = false) {
|
|
|
2348
2371
|
console.log(line);
|
|
2349
2372
|
}
|
|
2350
2373
|
}
|
|
2374
|
+
async function findVisibleLocatorWithin(page, selectors, timeoutMs) {
|
|
2375
|
+
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
2376
|
+
while (true) {
|
|
2377
|
+
const found = await findVisibleLocator(page, selectors);
|
|
2378
|
+
if (found) return found;
|
|
2379
|
+
if (Date.now() >= deadline) return null;
|
|
2380
|
+
await sleep(Math.min(150, Math.max(1, deadline - Date.now())));
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
async function waitForHidden(locator, timeoutMs) {
|
|
2384
|
+
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
2385
|
+
while (true) {
|
|
2386
|
+
if (!await isVisible(locator)) return true;
|
|
2387
|
+
if (Date.now() >= deadline) return false;
|
|
2388
|
+
await sleep(Math.min(100, Math.max(1, deadline - Date.now())));
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
async function computeAliyunPuzzleOffset(page) {
|
|
2392
|
+
return page.evaluate(() => {
|
|
2393
|
+
const background = document.querySelector(
|
|
2394
|
+
"#aliyunCaptcha-img"
|
|
2395
|
+
);
|
|
2396
|
+
const piece = document.querySelector(
|
|
2397
|
+
"#aliyunCaptcha-puzzle"
|
|
2398
|
+
);
|
|
2399
|
+
if (!background || !piece) {
|
|
2400
|
+
return Promise.resolve({ ok: false, reason: "missing puzzle images" });
|
|
2401
|
+
}
|
|
2402
|
+
const compute = () => {
|
|
2403
|
+
try {
|
|
2404
|
+
const width = background.naturalWidth;
|
|
2405
|
+
const height = background.naturalHeight;
|
|
2406
|
+
const pieceWidth = piece.naturalWidth;
|
|
2407
|
+
const pieceHeight = piece.naturalHeight;
|
|
2408
|
+
if (!width || !height || !pieceWidth || !pieceHeight) {
|
|
2409
|
+
return { ok: false, reason: "image dimensions unavailable" };
|
|
2410
|
+
}
|
|
2411
|
+
const backgroundCanvas = document.createElement("canvas");
|
|
2412
|
+
backgroundCanvas.id = "captcha-solver-canvas";
|
|
2413
|
+
backgroundCanvas.width = width;
|
|
2414
|
+
backgroundCanvas.height = height;
|
|
2415
|
+
const backgroundContext = backgroundCanvas.getContext("2d");
|
|
2416
|
+
if (!backgroundContext) {
|
|
2417
|
+
return { ok: false, reason: "no background context" };
|
|
2418
|
+
}
|
|
2419
|
+
const pieceCanvas = document.createElement("canvas");
|
|
2420
|
+
pieceCanvas.id = "captcha-solver-canvas";
|
|
2421
|
+
pieceCanvas.width = pieceWidth;
|
|
2422
|
+
pieceCanvas.height = pieceHeight;
|
|
2423
|
+
const pieceContext = pieceCanvas.getContext("2d");
|
|
2424
|
+
if (!pieceContext) {
|
|
2425
|
+
return { ok: false, reason: "no piece context" };
|
|
2426
|
+
}
|
|
2427
|
+
try {
|
|
2428
|
+
backgroundContext.drawImage(background, 0, 0);
|
|
2429
|
+
} catch {
|
|
2430
|
+
return { ok: false, reason: "background canvas tainted" };
|
|
2431
|
+
}
|
|
2432
|
+
try {
|
|
2433
|
+
pieceContext.drawImage(piece, 0, 0);
|
|
2434
|
+
} catch {
|
|
2435
|
+
return { ok: false, reason: "puzzle canvas tainted" };
|
|
2436
|
+
}
|
|
2437
|
+
const backgroundData = backgroundContext.getImageData(
|
|
2438
|
+
0,
|
|
2439
|
+
0,
|
|
2440
|
+
width,
|
|
2441
|
+
height
|
|
2442
|
+
).data;
|
|
2443
|
+
const pieceData = pieceContext.getImageData(
|
|
2444
|
+
0,
|
|
2445
|
+
0,
|
|
2446
|
+
pieceWidth,
|
|
2447
|
+
pieceHeight
|
|
2448
|
+
).data;
|
|
2449
|
+
let pieceMinX = pieceWidth;
|
|
2450
|
+
let pieceMaxX = -1;
|
|
2451
|
+
let pieceMinY = pieceHeight;
|
|
2452
|
+
let pieceMaxY = -1;
|
|
2453
|
+
for (let y = 0; y < pieceHeight; y++) {
|
|
2454
|
+
for (let x = 0; x < pieceWidth; x++) {
|
|
2455
|
+
if (pieceData[(y * pieceWidth + x) * 4 + 3] > 100) {
|
|
2456
|
+
if (x < pieceMinX) pieceMinX = x;
|
|
2457
|
+
if (x > pieceMaxX) pieceMaxX = x;
|
|
2458
|
+
if (y < pieceMinY) pieceMinY = y;
|
|
2459
|
+
if (y > pieceMaxY) pieceMaxY = y;
|
|
2460
|
+
}
|
|
2461
|
+
}
|
|
2462
|
+
}
|
|
2463
|
+
const puzzleWidth = pieceMaxX - pieceMinX + 1;
|
|
2464
|
+
if (puzzleWidth <= 0) {
|
|
2465
|
+
return { ok: false, reason: "empty puzzle piece" };
|
|
2466
|
+
}
|
|
2467
|
+
const yStart = Math.max(1, Math.min(height - 2, pieceMinY + 5));
|
|
2468
|
+
const yEnd = Math.max(
|
|
2469
|
+
yStart,
|
|
2470
|
+
Math.min(height - 2, pieceMaxY - 5)
|
|
2471
|
+
);
|
|
2472
|
+
const columnGradients = new Float32Array(width);
|
|
2473
|
+
for (let x = 1; x < width - 1; x++) {
|
|
2474
|
+
let gradient = 0;
|
|
2475
|
+
for (let y = yStart; y <= yEnd; y++) {
|
|
2476
|
+
const left = (y * width + x - 1) * 4;
|
|
2477
|
+
const right = (y * width + x + 1) * 4;
|
|
2478
|
+
gradient += Math.abs(backgroundData[right] - backgroundData[left]) + Math.abs(backgroundData[right + 1] - backgroundData[left + 1]) + Math.abs(backgroundData[right + 2] - backgroundData[left + 2]);
|
|
2479
|
+
}
|
|
2480
|
+
columnGradients[x] = gradient;
|
|
2481
|
+
}
|
|
2482
|
+
let bestX = 0;
|
|
2483
|
+
let bestScore = 0;
|
|
2484
|
+
const minCandidateX = 30;
|
|
2485
|
+
const maxCandidateX = width - puzzleWidth - 20;
|
|
2486
|
+
for (let candidateX = minCandidateX; candidateX <= maxCandidateX; candidateX++) {
|
|
2487
|
+
let leftMax = 0;
|
|
2488
|
+
for (let dx = -2; dx <= 2; dx++) {
|
|
2489
|
+
const value = columnGradients[candidateX + pieceMinX + dx] || 0;
|
|
2490
|
+
if (value > leftMax) leftMax = value;
|
|
2491
|
+
}
|
|
2492
|
+
let rightMax = 0;
|
|
2493
|
+
for (let dx = -3; dx <= 1; dx++) {
|
|
2494
|
+
const value = columnGradients[candidateX + pieceMaxX + dx] || 0;
|
|
2495
|
+
if (value > rightMax) rightMax = value;
|
|
2496
|
+
}
|
|
2497
|
+
const score = Math.sqrt(leftMax * rightMax);
|
|
2498
|
+
if (score > bestScore) {
|
|
2499
|
+
bestScore = score;
|
|
2500
|
+
bestX = candidateX;
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
if (bestScore <= 0) {
|
|
2504
|
+
return { ok: false, reason: "no matching hole edge" };
|
|
2505
|
+
}
|
|
2506
|
+
return {
|
|
2507
|
+
ok: true,
|
|
2508
|
+
offsetX: bestX - pieceMinX,
|
|
2509
|
+
naturalWidth: width
|
|
2510
|
+
};
|
|
2511
|
+
} catch (error) {
|
|
2512
|
+
return {
|
|
2513
|
+
ok: false,
|
|
2514
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
2515
|
+
};
|
|
2516
|
+
}
|
|
2517
|
+
};
|
|
2518
|
+
return new Promise((resolve) => {
|
|
2519
|
+
if (background.complete && piece.complete) {
|
|
2520
|
+
resolve(compute());
|
|
2521
|
+
return;
|
|
2522
|
+
}
|
|
2523
|
+
let settled = false;
|
|
2524
|
+
const finish = () => {
|
|
2525
|
+
if (settled) return;
|
|
2526
|
+
settled = true;
|
|
2527
|
+
resolve(compute());
|
|
2528
|
+
};
|
|
2529
|
+
const fail = () => {
|
|
2530
|
+
if (settled) return;
|
|
2531
|
+
settled = true;
|
|
2532
|
+
resolve({ ok: false, reason: "puzzle image load error" });
|
|
2533
|
+
};
|
|
2534
|
+
background.addEventListener("load", finish, { once: true });
|
|
2535
|
+
piece.addEventListener("load", finish, { once: true });
|
|
2536
|
+
background.addEventListener("error", fail, { once: true });
|
|
2537
|
+
piece.addEventListener("error", fail, { once: true });
|
|
2538
|
+
setTimeout(() => {
|
|
2539
|
+
if (settled) return;
|
|
2540
|
+
settled = true;
|
|
2541
|
+
resolve({ ok: false, reason: "puzzle image load timeout" });
|
|
2542
|
+
}, 2e3);
|
|
2543
|
+
});
|
|
2544
|
+
});
|
|
2545
|
+
}
|
|
2546
|
+
async function solveAliyunWafCaptcha(page, options = {}) {
|
|
2547
|
+
const waitForMs = Math.max(0, options.waitForMs ?? 0);
|
|
2548
|
+
const maxAttempts = Math.max(
|
|
2549
|
+
1,
|
|
2550
|
+
Math.min(5, options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS)
|
|
2551
|
+
);
|
|
2552
|
+
const retryDelayMs = Math.max(
|
|
2553
|
+
0,
|
|
2554
|
+
options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS
|
|
2555
|
+
);
|
|
2556
|
+
const settleMs = Math.max(0, options.settleMs ?? DEFAULT_SETTLE_MS);
|
|
2557
|
+
const sliderTimeoutMs = Math.max(
|
|
2558
|
+
500,
|
|
2559
|
+
options.sliderTimeoutMs ?? DEFAULT_SLIDER_TIMEOUT_MS
|
|
2560
|
+
);
|
|
2561
|
+
const detected = await findVisibleLocatorWithin(
|
|
2562
|
+
page,
|
|
2563
|
+
ALIYUN_WAF_BLOCK_SELECTORS,
|
|
2564
|
+
waitForMs
|
|
2565
|
+
);
|
|
2566
|
+
if (!detected) return false;
|
|
2567
|
+
return withCaptchaMouseLock(async () => {
|
|
2568
|
+
const block = detected.locator;
|
|
2569
|
+
if (!await isVisible(block)) return false;
|
|
2570
|
+
logBaxiaCaptcha("aliyun_detected", { selector: detected.selector });
|
|
2571
|
+
let lastReason = "unknown";
|
|
2572
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
2573
|
+
try {
|
|
2574
|
+
const offset = await computeAliyunPuzzleOffset(page);
|
|
2575
|
+
if (!offset.ok || typeof offset.offsetX !== "number" || typeof offset.naturalWidth !== "number" || offset.naturalWidth <= 0) {
|
|
2576
|
+
lastReason = offset.reason || "offset_unavailable";
|
|
2577
|
+
logBaxiaCaptcha("aliyun_offset_failed", {
|
|
2578
|
+
attempt,
|
|
2579
|
+
reason: lastReason
|
|
2580
|
+
});
|
|
2581
|
+
} else {
|
|
2582
|
+
const slider = page.locator(ALIYUN_PUZZLE_SLIDER_SELECTOR).first();
|
|
2583
|
+
const track = page.locator(ALIYUN_PUZZLE_TRACK_SELECTOR).first();
|
|
2584
|
+
await slider.waitFor({ state: "visible", timeout: sliderTimeoutMs });
|
|
2585
|
+
const [sliderBox, trackBox] = await Promise.all([
|
|
2586
|
+
slider.boundingBox(),
|
|
2587
|
+
track.boundingBox()
|
|
2588
|
+
]);
|
|
2589
|
+
if (!sliderBox || !trackBox || trackBox.width <= 0) {
|
|
2590
|
+
lastReason = "bounds_unavailable";
|
|
2591
|
+
logBaxiaCaptcha("aliyun_offset_failed", {
|
|
2592
|
+
attempt,
|
|
2593
|
+
reason: lastReason
|
|
2594
|
+
});
|
|
2595
|
+
} else {
|
|
2596
|
+
const scale = trackBox.width / offset.naturalWidth;
|
|
2597
|
+
const dragDistance = Math.round(offset.offsetX * scale);
|
|
2598
|
+
logBaxiaCaptcha("aliyun_geometry", {
|
|
2599
|
+
attempt,
|
|
2600
|
+
offset: offset.offsetX,
|
|
2601
|
+
scale: Number(scale.toFixed(2)),
|
|
2602
|
+
distance: dragDistance
|
|
2603
|
+
});
|
|
2604
|
+
if (dragDistance <= 0) {
|
|
2605
|
+
lastReason = "non_positive_distance";
|
|
2606
|
+
} else {
|
|
2607
|
+
const startX = sliderBox.x + sliderBox.width / 2;
|
|
2608
|
+
const startY = sliderBox.y + sliderBox.height / 2;
|
|
2609
|
+
await humanDrag(
|
|
2610
|
+
page,
|
|
2611
|
+
startX,
|
|
2612
|
+
startY,
|
|
2613
|
+
startX + dragDistance,
|
|
2614
|
+
startY
|
|
2615
|
+
);
|
|
2616
|
+
if (await waitForHidden(block, settleMs)) {
|
|
2617
|
+
logBaxiaCaptcha(
|
|
2618
|
+
"aliyun_solve_succeeded",
|
|
2619
|
+
{ attempt, distance: dragDistance },
|
|
2620
|
+
true
|
|
2621
|
+
);
|
|
2622
|
+
return true;
|
|
2623
|
+
}
|
|
2624
|
+
lastReason = "not_solved";
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
} catch (error) {
|
|
2629
|
+
lastReason = error instanceof Error ? error.name : "UnknownError";
|
|
2630
|
+
logBaxiaCaptcha("aliyun_offset_failed", {
|
|
2631
|
+
attempt,
|
|
2632
|
+
error: lastReason,
|
|
2633
|
+
detail: sanitizeCaptchaErrorDetail(error)
|
|
2634
|
+
});
|
|
2635
|
+
}
|
|
2636
|
+
if (attempt < maxAttempts && retryDelayMs > 0) {
|
|
2637
|
+
await sleep(retryDelayMs);
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
logBaxiaCaptcha(
|
|
2641
|
+
"aliyun_solve_failed",
|
|
2642
|
+
{ attempts: maxAttempts, reason: lastReason },
|
|
2643
|
+
true
|
|
2644
|
+
);
|
|
2645
|
+
return false;
|
|
2646
|
+
});
|
|
2647
|
+
}
|
|
2648
|
+
async function solveVisibleCaptcha(page, options = {}) {
|
|
2649
|
+
if (typeof page.isClosed === "function" && page.isClosed()) return false;
|
|
2650
|
+
const totalWaitMs = Math.max(0, options.waitForMs ?? 0);
|
|
2651
|
+
const aliyunWaitMs = Math.min(totalWaitMs, ALIYUN_PROBE_MAX_WAIT_MS);
|
|
2652
|
+
const startedAt = Date.now();
|
|
2653
|
+
if (await solveAliyunWafCaptcha(page, { ...options, waitForMs: aliyunWaitMs })) {
|
|
2654
|
+
return true;
|
|
2655
|
+
}
|
|
2656
|
+
const remainingWaitMs = Math.max(
|
|
2657
|
+
0,
|
|
2658
|
+
totalWaitMs - (Date.now() - startedAt)
|
|
2659
|
+
);
|
|
2660
|
+
return solveBaxiaCaptcha(page, { ...options, waitForMs: remainingWaitMs });
|
|
2661
|
+
}
|
|
2351
2662
|
async function isVisible(locator) {
|
|
2352
2663
|
return locator.isVisible().catch(() => false);
|
|
2353
2664
|
}
|
|
@@ -2590,7 +2901,7 @@ async function solveBaxiaCaptchaUnlocked(page, options = {}) {
|
|
|
2590
2901
|
);
|
|
2591
2902
|
return false;
|
|
2592
2903
|
}
|
|
2593
|
-
var BAXIA_DIALOG_SELECTOR, BAXIA_CONTENT_SELECTOR, CAPTCHA_EVENT_EMOJI, captchaDebugEnabled, BAXIA_IFRAME_SELECTORS, BAXIA_DOCUMENT_SELECTORS, BAXIA_IFRAME_SELECTOR, BAXIA_SLIDER_SELECTOR, BAXIA_TRACK_SELECTOR, BAXIA_SUCCESS_SELECTOR, BAXIA_RELOAD_SELECTOR, DEFAULT_MAX_ATTEMPTS, DEFAULT_RETRY_DELAY_MS, DEFAULT_SETTLE_MS, DEFAULT_SLIDER_TIMEOUT_MS, captchaMouseLock;
|
|
2904
|
+
var BAXIA_DIALOG_SELECTOR, BAXIA_CONTENT_SELECTOR, CAPTCHA_EVENT_EMOJI, captchaDebugEnabled, BAXIA_IFRAME_SELECTORS, BAXIA_DOCUMENT_SELECTORS, BAXIA_IFRAME_SELECTOR, BAXIA_SLIDER_SELECTOR, BAXIA_TRACK_SELECTOR, BAXIA_SUCCESS_SELECTOR, BAXIA_RELOAD_SELECTOR, DEFAULT_MAX_ATTEMPTS, DEFAULT_RETRY_DELAY_MS, DEFAULT_SETTLE_MS, DEFAULT_SLIDER_TIMEOUT_MS, ALIYUN_WAF_CAPTCHA_SELECTOR, ALIYUN_WAF_CAPTCHA_WIDGET, ALIYUN_WAF_BLOCK_SELECTORS, ALIYUN_PUZZLE_SLIDER_SELECTOR, ALIYUN_PUZZLE_TRACK_SELECTOR, ALIYUN_PROBE_MAX_WAIT_MS, captchaMouseLock;
|
|
2594
2905
|
var init_captcha_solver = __esm({
|
|
2595
2906
|
"src/services/captcha-solver.ts"() {
|
|
2596
2907
|
"use strict";
|
|
@@ -2616,14 +2927,20 @@ var init_captcha_solver = __esm({
|
|
|
2616
2927
|
solve_failed: "\u274C",
|
|
2617
2928
|
recovery_succeeded: "\u2705",
|
|
2618
2929
|
recovery_not_solved: "\u26A0\uFE0F",
|
|
2619
|
-
recovery_failed: "\u274C"
|
|
2930
|
+
recovery_failed: "\u274C",
|
|
2931
|
+
aliyun_detected: "\u{1F9E9}",
|
|
2932
|
+
aliyun_offset_failed: "\u{1F4D0}",
|
|
2933
|
+
aliyun_geometry: "\u{1F4D0}",
|
|
2934
|
+
aliyun_solve_succeeded: "\u2705",
|
|
2935
|
+
aliyun_solve_failed: "\u274C"
|
|
2620
2936
|
};
|
|
2621
2937
|
captchaDebugEnabled = process.env.CAPTCHA_DEBUG === "true";
|
|
2622
2938
|
BAXIA_IFRAME_SELECTORS = [
|
|
2623
2939
|
`${BAXIA_DIALOG_SELECTOR} ${BAXIA_CONTENT_SELECTOR} iframe`,
|
|
2624
2940
|
`${BAXIA_CONTENT_SELECTOR} iframe`,
|
|
2625
2941
|
"iframe#baxia-dialog-content",
|
|
2626
|
-
'iframe[src*="_____tmd_____/punish"]'
|
|
2942
|
+
'iframe[src*="_____tmd_____/punish"]',
|
|
2943
|
+
'iframe[src*="nocaptcha"]'
|
|
2627
2944
|
];
|
|
2628
2945
|
BAXIA_DOCUMENT_SELECTORS = [
|
|
2629
2946
|
"#nocaptcha",
|
|
@@ -2631,14 +2948,23 @@ var init_captcha_solver = __esm({
|
|
|
2631
2948
|
"#baxia-punish"
|
|
2632
2949
|
];
|
|
2633
2950
|
BAXIA_IFRAME_SELECTOR = BAXIA_IFRAME_SELECTORS.join(", ");
|
|
2634
|
-
BAXIA_SLIDER_SELECTOR =
|
|
2635
|
-
BAXIA_TRACK_SELECTOR =
|
|
2951
|
+
BAXIA_SLIDER_SELECTOR = '#nc_1_n1z, .nc_1_n1z, .btn_slide, .nc_iconfont.btn_slide, span[id*="_n1z"], .nc_wrapper .btn_slide, ._nc .btn_slide, .nc-container .btn_slide';
|
|
2952
|
+
BAXIA_TRACK_SELECTOR = '#nc_1_n1t, .nc_scale, span[id*="_n1t"], .nc_wrapper .nc_scale, ._nc .nc_scale, .nc-container .nc_scale';
|
|
2636
2953
|
BAXIA_SUCCESS_SELECTOR = '.btn_ok, .nc_ok, .nc_success, .nc_result, .nc_wrapper.nc-success, .nc_wrapper.success, [data-nc-lang="SUCCESS"], [data-nc-lang="success"], #nc-loading-circle';
|
|
2637
2954
|
BAXIA_RELOAD_SELECTOR = '#nc_1_refresh1, .errloading a, .nc-container .errloading a, .btn_refresh, .clickCaptcha_text .btn_refresh, [data-nc-lang="REFRESH"], a[id*="refresh"]';
|
|
2638
2955
|
DEFAULT_MAX_ATTEMPTS = 3;
|
|
2639
2956
|
DEFAULT_RETRY_DELAY_MS = 1e3;
|
|
2640
2957
|
DEFAULT_SETTLE_MS = 2e3;
|
|
2641
2958
|
DEFAULT_SLIDER_TIMEOUT_MS = 8e3;
|
|
2959
|
+
ALIYUN_WAF_CAPTCHA_SELECTOR = "#waf_nc_block";
|
|
2960
|
+
ALIYUN_WAF_CAPTCHA_WIDGET = "#aliyunCaptcha-window-embed";
|
|
2961
|
+
ALIYUN_WAF_BLOCK_SELECTORS = [
|
|
2962
|
+
ALIYUN_WAF_CAPTCHA_SELECTOR,
|
|
2963
|
+
ALIYUN_WAF_CAPTCHA_WIDGET
|
|
2964
|
+
];
|
|
2965
|
+
ALIYUN_PUZZLE_SLIDER_SELECTOR = "#aliyunCaptcha-sliding-slider";
|
|
2966
|
+
ALIYUN_PUZZLE_TRACK_SELECTOR = "#aliyunCaptcha-sliding-body";
|
|
2967
|
+
ALIYUN_PROBE_MAX_WAIT_MS = 2e3;
|
|
2642
2968
|
captchaMouseLock = Promise.resolve();
|
|
2643
2969
|
}
|
|
2644
2970
|
});
|
|
@@ -2729,7 +3055,15 @@ function updateQwenWebVersion(version) {
|
|
|
2729
3055
|
function getQwenWebVersion() {
|
|
2730
3056
|
return dynamicWebVersion || config.qwen.webVersion;
|
|
2731
3057
|
}
|
|
2732
|
-
|
|
3058
|
+
function updateQwenBxVersion(version) {
|
|
3059
|
+
if (version && typeof version === "string" && /^\d+\.\d+\.\d+/.test(version)) {
|
|
3060
|
+
dynamicBxVersion = version.trim();
|
|
3061
|
+
}
|
|
3062
|
+
}
|
|
3063
|
+
function getQwenBxVersion() {
|
|
3064
|
+
return dynamicBxVersion || config.auth.bxV;
|
|
3065
|
+
}
|
|
3066
|
+
var dynamicWebVersion, dynamicBxVersion, QWEN_WEB_VERSION, DEFAULT_QWEN_USER_AGENT, QWEN_TIMEZONE_HEADER;
|
|
2733
3067
|
var init_qwen_headers = __esm({
|
|
2734
3068
|
"src/services/qwen-headers.ts"() {
|
|
2735
3069
|
"use strict";
|
|
@@ -2738,6 +3072,7 @@ var init_qwen_headers = __esm({
|
|
|
2738
3072
|
init_fingerprint();
|
|
2739
3073
|
init_timezone();
|
|
2740
3074
|
dynamicWebVersion = null;
|
|
3075
|
+
dynamicBxVersion = null;
|
|
2741
3076
|
QWEN_WEB_VERSION = config.qwen.webVersion;
|
|
2742
3077
|
DEFAULT_QWEN_USER_AGENT = getDefaultQwenUserAgent(151);
|
|
2743
3078
|
QWEN_TIMEZONE_HEADER = (/* @__PURE__ */ new Date()).toString().split(" (")[0];
|
|
@@ -3054,11 +3389,12 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
|
|
|
3054
3389
|
async function clearVisibleChallenge(page) {
|
|
3055
3390
|
if (page.isClosed()) return;
|
|
3056
3391
|
if (config.captcha.enabled) {
|
|
3057
|
-
await
|
|
3392
|
+
await solveVisibleCaptcha(page, {
|
|
3058
3393
|
waitForMs: 0,
|
|
3059
3394
|
maxAttempts: config.captcha.maxAttempts,
|
|
3060
3395
|
retryDelayMs: config.captcha.retryDelayMs,
|
|
3061
|
-
settleMs: config.captcha.settleMs
|
|
3396
|
+
settleMs: config.captcha.settleMs,
|
|
3397
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
3062
3398
|
}).catch(() => false);
|
|
3063
3399
|
}
|
|
3064
3400
|
try {
|
|
@@ -3623,8 +3959,12 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
3623
3959
|
if (accountPages.has(account.id)) {
|
|
3624
3960
|
return;
|
|
3625
3961
|
}
|
|
3626
|
-
|
|
3627
|
-
|
|
3962
|
+
if (config.playwright.maxActiveContexts > 0) {
|
|
3963
|
+
await evictIdlePlaywrightContextsToLimit(
|
|
3964
|
+
Math.max(1, config.playwright.maxActiveContexts - 1)
|
|
3965
|
+
).catch(() => {
|
|
3966
|
+
});
|
|
3967
|
+
}
|
|
3628
3968
|
const profilePath = getAccountProfilePath(account.id);
|
|
3629
3969
|
const fingerprint = getFingerprintProfile(account.id);
|
|
3630
3970
|
const { engine, channel } = resolveBrowserEngine(browserType);
|
|
@@ -3800,6 +4140,9 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
3800
4140
|
if (persisted.version) {
|
|
3801
4141
|
updateQwenWebVersion(persisted.version);
|
|
3802
4142
|
}
|
|
4143
|
+
if (persisted.bxV) {
|
|
4144
|
+
updateQwenBxVersion(persisted.bxV);
|
|
4145
|
+
}
|
|
3803
4146
|
cache.lastRefresh = persisted.capturedAt;
|
|
3804
4147
|
markAccountHeadersReady(account.id);
|
|
3805
4148
|
restoredFromDb = true;
|
|
@@ -3893,7 +4236,7 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
3893
4236
|
if (!acctPage.isClosed()) {
|
|
3894
4237
|
try {
|
|
3895
4238
|
const currentUrl = new URL(acctPage.url());
|
|
3896
|
-
if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname
|
|
4239
|
+
if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname.includes("/auth") || currentUrl.pathname.includes("/login") || currentUrl.pathname.includes("_____tmd_____")) {
|
|
3897
4240
|
await acctPage.goto(qwenUrl("/"), {
|
|
3898
4241
|
waitUntil: "domcontentloaded",
|
|
3899
4242
|
timeout: config.timeouts.navigation
|
|
@@ -3911,6 +4254,8 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
3911
4254
|
} finally {
|
|
3912
4255
|
release();
|
|
3913
4256
|
}
|
|
4257
|
+
await evictIdlePlaywrightContextsToLimit().catch(() => {
|
|
4258
|
+
});
|
|
3914
4259
|
})();
|
|
3915
4260
|
try {
|
|
3916
4261
|
await initPromise;
|
|
@@ -3994,7 +4339,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
3994
4339
|
saveAuthSession2(accountId, {
|
|
3995
4340
|
cookie: cookieStr,
|
|
3996
4341
|
userAgent: cache.headers["user-agent"] || "",
|
|
3997
|
-
bxV: cache.headers["bx-v"] ||
|
|
4342
|
+
bxV: cache.headers["bx-v"] || getQwenBxVersion(),
|
|
3998
4343
|
bxUa: cache.headers["bx-ua"] || "",
|
|
3999
4344
|
bxUmidtoken: cache.headers["bx-umidtoken"] || "",
|
|
4000
4345
|
secChUa: cache.headers["sec-ch-ua"] || void 0,
|
|
@@ -4066,7 +4411,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4066
4411
|
saveAuthSession2(accountId, {
|
|
4067
4412
|
cookie: cookieStr,
|
|
4068
4413
|
userAgent: cache.headers["user-agent"] || "",
|
|
4069
|
-
bxV: cache.headers["bx-v"] ||
|
|
4414
|
+
bxV: cache.headers["bx-v"] || getQwenBxVersion(),
|
|
4070
4415
|
bxUa: cache.headers["bx-ua"] || "",
|
|
4071
4416
|
bxUmidtoken: cache.headers["bx-umidtoken"] || "",
|
|
4072
4417
|
secChUa: cache.headers["sec-ch-ua"] || void 0,
|
|
@@ -4137,7 +4482,7 @@ async function loginViaApi(page, email, password) {
|
|
|
4137
4482
|
}
|
|
4138
4483
|
const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
|
|
4139
4484
|
const requestId = crypto3.randomUUID();
|
|
4140
|
-
const webVersion = getQwenWebVersion()
|
|
4485
|
+
const webVersion = getQwenWebVersion();
|
|
4141
4486
|
const evalRes = await page.evaluate(
|
|
4142
4487
|
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz, version }) => {
|
|
4143
4488
|
try {
|
|
@@ -4309,6 +4654,15 @@ async function loginViaUi(page, email, password) {
|
|
|
4309
4654
|
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
|
|
4310
4655
|
return { success: true };
|
|
4311
4656
|
}
|
|
4657
|
+
if (config.captcha.enabled) {
|
|
4658
|
+
await solveVisibleCaptcha(page, {
|
|
4659
|
+
waitForMs: 1500,
|
|
4660
|
+
maxAttempts: config.captcha.maxAttempts,
|
|
4661
|
+
retryDelayMs: config.captcha.retryDelayMs,
|
|
4662
|
+
settleMs: config.captcha.settleMs,
|
|
4663
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
4664
|
+
}).catch(() => false);
|
|
4665
|
+
}
|
|
4312
4666
|
const emailSelector = [
|
|
4313
4667
|
'input[type="email"]',
|
|
4314
4668
|
'input[name="email"]',
|
|
@@ -4464,10 +4818,11 @@ async function loginViaUi(page, email, password) {
|
|
|
4464
4818
|
while (Date.now() < postSubmitDeadline) {
|
|
4465
4819
|
if (page.isClosed()) break;
|
|
4466
4820
|
if (config.captcha.enabled) {
|
|
4467
|
-
await
|
|
4821
|
+
await solveVisibleCaptcha(page, {
|
|
4468
4822
|
waitForMs: 1500,
|
|
4469
4823
|
maxAttempts: config.captcha.maxAttempts,
|
|
4470
|
-
retryDelayMs: config.captcha.retryDelayMs
|
|
4824
|
+
retryDelayMs: config.captcha.retryDelayMs,
|
|
4825
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
4471
4826
|
}).catch(() => {
|
|
4472
4827
|
});
|
|
4473
4828
|
}
|
|
@@ -4590,7 +4945,7 @@ async function refreshAccountToken(accountId) {
|
|
|
4590
4945
|
}
|
|
4591
4946
|
if (refreshToken) {
|
|
4592
4947
|
try {
|
|
4593
|
-
const webVersion = getQwenWebVersion()
|
|
4948
|
+
const webVersion = getQwenWebVersion();
|
|
4594
4949
|
const refreshResult = await page.evaluate(
|
|
4595
4950
|
async ({ rTok, tz, version }) => {
|
|
4596
4951
|
try {
|
|
@@ -4655,7 +5010,7 @@ async function refreshAccountToken(accountId) {
|
|
|
4655
5010
|
saveAuthSession2(accountId, {
|
|
4656
5011
|
cookie: cookieStr,
|
|
4657
5012
|
userAgent: cache.headers["user-agent"] || session?.userAgent || "",
|
|
4658
|
-
bxV: cache.headers["bx-v"] || session?.bxV ||
|
|
5013
|
+
bxV: cache.headers["bx-v"] || session?.bxV || getQwenBxVersion(),
|
|
4659
5014
|
bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
|
|
4660
5015
|
bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
|
|
4661
5016
|
secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
|
|
@@ -4690,7 +5045,7 @@ async function refreshAccountToken(accountId) {
|
|
|
4690
5045
|
saveAuthSession2(accountId, {
|
|
4691
5046
|
cookie: cookieStr,
|
|
4692
5047
|
userAgent: cache.headers["user-agent"] || session?.userAgent || "",
|
|
4693
|
-
bxV: cache.headers["bx-v"] || session?.bxV ||
|
|
5048
|
+
bxV: cache.headers["bx-v"] || session?.bxV || getQwenBxVersion(),
|
|
4694
5049
|
bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
|
|
4695
5050
|
bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
|
|
4696
5051
|
secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
|
|
@@ -4838,7 +5193,7 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
4838
5193
|
cookie: reqHeaders["cookie"] || "",
|
|
4839
5194
|
"bx-ua": reqHeaders["bx-ua"] || "",
|
|
4840
5195
|
"bx-umidtoken": reqHeaders["bx-umidtoken"] || "",
|
|
4841
|
-
"bx-v": reqHeaders["bx-v"] ||
|
|
5196
|
+
"bx-v": reqHeaders["bx-v"] || getQwenBxVersion(),
|
|
4842
5197
|
"user-agent": reqHeaders["user-agent"] || "",
|
|
4843
5198
|
"x-request-id": reqHeaders["x-request-id"] || "",
|
|
4844
5199
|
"version": reqHeaders["version"] || "",
|
|
@@ -4870,6 +5225,9 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
4870
5225
|
if (capturedHeaders["version"]) {
|
|
4871
5226
|
updateQwenWebVersion(capturedHeaders["version"]);
|
|
4872
5227
|
}
|
|
5228
|
+
if (capturedHeaders["bx-v"]) {
|
|
5229
|
+
updateQwenBxVersion(capturedHeaders["bx-v"]);
|
|
5230
|
+
}
|
|
4873
5231
|
markAccountHeadersReady(accountId);
|
|
4874
5232
|
cache.lastRefresh = Date.now();
|
|
4875
5233
|
cookieCaches.delete(accountId);
|
|
@@ -5413,7 +5771,11 @@ function priorityOrderForEviction(accountIds) {
|
|
|
5413
5771
|
const ranked = getAccountsByPriority(accountIds.map((id) => ({ id })));
|
|
5414
5772
|
const rank = /* @__PURE__ */ new Map();
|
|
5415
5773
|
for (const [index, account] of ranked.entries()) {
|
|
5416
|
-
|
|
5774
|
+
if (getAccountCooldownInfo(account.id)) {
|
|
5775
|
+
rank.set(account.id, Number.MAX_SAFE_INTEGER);
|
|
5776
|
+
} else {
|
|
5777
|
+
rank.set(account.id, index);
|
|
5778
|
+
}
|
|
5417
5779
|
}
|
|
5418
5780
|
return orderContextsForEviction(
|
|
5419
5781
|
accountIds,
|
|
@@ -5421,14 +5783,15 @@ function priorityOrderForEviction(accountIds) {
|
|
|
5421
5783
|
(id) => lastAccountActivity.get(id) ?? 0
|
|
5422
5784
|
);
|
|
5423
5785
|
}
|
|
5424
|
-
async function evictIdlePlaywrightContextsToLimit() {
|
|
5425
|
-
const
|
|
5426
|
-
if (
|
|
5786
|
+
async function evictIdlePlaywrightContextsToLimit(targetLimit) {
|
|
5787
|
+
const configuredMax = config.playwright.maxActiveContexts;
|
|
5788
|
+
if (configuredMax <= 0) return 0;
|
|
5789
|
+
const max = targetLimit !== void 0 ? Math.max(0, targetLimit) : configuredMax;
|
|
5427
5790
|
if (accountPages.size <= max) return 0;
|
|
5428
5791
|
const candidates = priorityOrderForEviction(
|
|
5429
5792
|
Array.from(accountPages.keys()).filter((accountId) => {
|
|
5430
5793
|
if (isAccountServingStream(accountId)) return false;
|
|
5431
|
-
if (
|
|
5794
|
+
if (hasActiveAccountLease(accountId)) return false;
|
|
5432
5795
|
const mutex = accountMutexes.get(accountId);
|
|
5433
5796
|
return mutex?.isIdle();
|
|
5434
5797
|
})
|
|
@@ -5441,6 +5804,7 @@ async function evictIdlePlaywrightContextsToLimit() {
|
|
|
5441
5804
|
for (const candidate of candidates) {
|
|
5442
5805
|
if (accountPages.size <= max) break;
|
|
5443
5806
|
if (isAccountServingStream(candidate.accountId)) continue;
|
|
5807
|
+
if (hasActiveAccountLease(candidate.accountId)) continue;
|
|
5444
5808
|
const mutex = accountMutexes.get(candidate.accountId);
|
|
5445
5809
|
if (!mutex?.isIdle()) continue;
|
|
5446
5810
|
await closePlaywrightForAccount(candidate.accountId).catch((error) => {
|
|
@@ -5543,10 +5907,6 @@ async function closePlaywrightForAccount(accountId) {
|
|
|
5543
5907
|
release();
|
|
5544
5908
|
}
|
|
5545
5909
|
}
|
|
5546
|
-
function isAccountRecentlyActive(accountId, maxIdleMs = 3e5) {
|
|
5547
|
-
const last = lastAccountActivity.get(accountId) ?? 0;
|
|
5548
|
-
return last > 0 && Date.now() - last < maxIdleMs;
|
|
5549
|
-
}
|
|
5550
5910
|
var requireLocal, contextInitHooks, ACCOUNT_MUTEX_MAX_HOLD_MS, accountMutexes, accountContexts, accountPages, inFlightAccountInits, headerCaches, HEADER_CACHE_TTL, COOKIE_CACHE_TTL, cookieCaches, lastAccountActivity, lastKeepAliveNavigation, lastProactiveTokenRefresh, profileResetQueue, profileResetChain, closingAllPlaywright, sleep2, HEADER_CAPTURE_SETTLE_MS, PLAYWRIGHT_MUTEX_WAIT_MS, ACCOUNT_PAGE_OPERATION_TIMEOUT_MS, SESSION_PROBE_NAVIGATION_TIMEOUT_MS, HEADER_CAPTURE_TRIGGER_GRACE_MS, FIRST_TRIGGER_GRACE_MS, HEADER_CAPTURE_TRIGGER_ATTEMPTS, CHAT_INPUT_APPEAR_TIMEOUT_MS, CHAT_INPUT_ACTION_TIMEOUT_MS, PROFILE_RESET_TIMEOUT_MS;
|
|
5551
5911
|
var init_playwright = __esm({
|
|
5552
5912
|
"src/services/playwright.ts"() {
|