aurix-ai 2.7.3 → 2.7.5
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/bin/aurix.js +2 -2
- package/dist/agent/AgentLoop.d.ts.map +1 -1
- package/dist/agent/AgentLoop.js +1 -52
- package/dist/agent/AgentLoop.js.map +1 -1
- package/dist/cli/App.d.ts.map +1 -1
- package/dist/cli/App.js +6 -0
- package/dist/cli/App.js.map +1 -1
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +7 -0
- package/dist/cli/commands.js.map +1 -1
- package/dist/tools/Browser.d.ts.map +1 -1
- package/dist/tools/Browser.js +44 -615
- package/dist/tools/Browser.js.map +1 -1
- package/dist/tools/captcha/CaptchaRouter.d.ts +6 -0
- package/dist/tools/captcha/CaptchaRouter.d.ts.map +1 -0
- package/dist/tools/captcha/CaptchaRouter.js +371 -0
- package/dist/tools/captcha/CaptchaRouter.js.map +1 -0
- package/dist/tools/captcha/RecaptchaSolver.d.ts +2 -0
- package/dist/tools/captcha/RecaptchaSolver.d.ts.map +1 -0
- package/dist/tools/captcha/RecaptchaSolver.js +1114 -0
- package/dist/tools/captcha/RecaptchaSolver.js.map +1 -0
- package/dist/tools/captcha/common.d.ts +35 -0
- package/dist/tools/captcha/common.d.ts.map +1 -0
- package/dist/tools/captcha/common.js +445 -0
- package/dist/tools/captcha/common.js.map +1 -0
- package/dist/tools/captcha/index.d.ts +5 -0
- package/dist/tools/captcha/index.d.ts.map +1 -0
- package/dist/tools/captcha/index.js +4 -0
- package/dist/tools/captcha/index.js.map +1 -0
- package/package.json +2 -2
- package/scripts/build.cjs +0 -15
- package/scripts/run-task.mjs +86 -0
- package/training/captcha-training.json +930 -0
- package/native/token-counter/index.d.ts +0 -7
- package/native/token-counter/index.js +0 -316
- package/native/token-counter/node_modules/.package-lock.json +0 -568
- package/native/token-counter/node_modules/2/array.js +0 -25
- package/native/token-counter/node_modules/2/index.js +0 -12
- package/native/token-counter/node_modules/2/iterator.js +0 -13
- package/native/token-counter/node_modules/2/license.txt +0 -21
- package/native/token-counter/node_modules/2/map.js +0 -27
- package/native/token-counter/node_modules/2/number.js +0 -109
- package/native/token-counter/node_modules/2/object.js +0 -23
- package/native/token-counter/node_modules/2/package.json +0 -60
- package/native/token-counter/node_modules/2/readme.md +0 -246
- package/native/token-counter/node_modules/2/string.js +0 -11
- package/native/token-counter/node_modules/2/test.js +0 -520
- package/native/token-counter/node_modules/@lamansky/every/index.js +0 -16
- package/native/token-counter/node_modules/@lamansky/every/license.txt +0 -21
- package/native/token-counter/node_modules/@lamansky/every/package.json +0 -38
- package/native/token-counter/node_modules/@lamansky/every/readme.md +0 -46
- package/native/token-counter/node_modules/@lamansky/flatten/index.js +0 -5
- package/native/token-counter/node_modules/@lamansky/flatten/license.txt +0 -21
- package/native/token-counter/node_modules/@lamansky/flatten/package.json +0 -35
- package/native/token-counter/node_modules/@lamansky/flatten/readme.md +0 -41
- package/native/token-counter/node_modules/@napi-rs/cli/LICENSE +0 -21
- package/native/token-counter/node_modules/@napi-rs/cli/README.md +0 -96
- package/native/token-counter/node_modules/@napi-rs/cli/package.json +0 -65
- package/native/token-counter/node_modules/@napi-rs/cli/scripts/index.js +0 -51371
- package/native/token-counter/node_modules/add-counter/index.js +0 -3
- package/native/token-counter/node_modules/add-counter/license.txt +0 -21
- package/native/token-counter/node_modules/add-counter/package.json +0 -34
- package/native/token-counter/node_modules/add-counter/readme.md +0 -36
- package/native/token-counter/node_modules/array-pad/LICENSE +0 -22
- package/native/token-counter/node_modules/array-pad/README.md +0 -80
- package/native/token-counter/node_modules/array-pad/index.js +0 -30
- package/native/token-counter/node_modules/array-pad/package.json +0 -28
- package/native/token-counter/node_modules/arrify/index.js +0 -8
- package/native/token-counter/node_modules/arrify/license +0 -21
- package/native/token-counter/node_modules/arrify/package.json +0 -33
- package/native/token-counter/node_modules/arrify/readme.md +0 -36
- package/native/token-counter/node_modules/case-insensitive/index.js +0 -72
- package/native/token-counter/node_modules/case-insensitive/license.txt +0 -21
- package/native/token-counter/node_modules/case-insensitive/package.json +0 -39
- package/native/token-counter/node_modules/case-insensitive/readme.md +0 -39
- package/native/token-counter/node_modules/case-insensitive/test.js +0 -114
- package/native/token-counter/node_modules/class-chain/index.js +0 -32
- package/native/token-counter/node_modules/class-chain/license.txt +0 -21
- package/native/token-counter/node_modules/class-chain/package.json +0 -39
- package/native/token-counter/node_modules/class-chain/readme.md +0 -23
- package/native/token-counter/node_modules/class-chain/test.js +0 -77
- package/native/token-counter/node_modules/copy-own/index.js +0 -10
- package/native/token-counter/node_modules/copy-own/license.txt +0 -21
- package/native/token-counter/node_modules/copy-own/package.json +0 -37
- package/native/token-counter/node_modules/copy-own/readme.md +0 -67
- package/native/token-counter/node_modules/def-props/index.js +0 -43
- package/native/token-counter/node_modules/def-props/license.txt +0 -21
- package/native/token-counter/node_modules/def-props/node_modules/is-obj/index.d.ts +0 -22
- package/native/token-counter/node_modules/def-props/node_modules/is-obj/index.js +0 -6
- package/native/token-counter/node_modules/def-props/node_modules/is-obj/license +0 -9
- package/native/token-counter/node_modules/def-props/node_modules/is-obj/package.json +0 -34
- package/native/token-counter/node_modules/def-props/node_modules/is-obj/readme.md +0 -39
- package/native/token-counter/node_modules/def-props/package.json +0 -51
- package/native/token-counter/node_modules/def-props/readme.md +0 -117
- package/native/token-counter/node_modules/empty-iterator/index.js +0 -3
- package/native/token-counter/node_modules/empty-iterator/license.txt +0 -21
- package/native/token-counter/node_modules/empty-iterator/package.json +0 -33
- package/native/token-counter/node_modules/empty-iterator/readme.md +0 -23
- package/native/token-counter/node_modules/enforce-range/index.js +0 -15
- package/native/token-counter/node_modules/enforce-range/license.txt +0 -21
- package/native/token-counter/node_modules/enforce-range/node_modules/2/array.js +0 -43
- package/native/token-counter/node_modules/enforce-range/node_modules/2/index.js +0 -10
- package/native/token-counter/node_modules/enforce-range/node_modules/2/iterator.js +0 -26
- package/native/token-counter/node_modules/enforce-range/node_modules/2/license.txt +0 -21
- package/native/token-counter/node_modules/enforce-range/node_modules/2/map.js +0 -47
- package/native/token-counter/node_modules/enforce-range/node_modules/2/number.js +0 -33
- package/native/token-counter/node_modules/enforce-range/node_modules/2/object.js +0 -61
- package/native/token-counter/node_modules/enforce-range/node_modules/2/package.json +0 -41
- package/native/token-counter/node_modules/enforce-range/node_modules/2/readme.md +0 -210
- package/native/token-counter/node_modules/enforce-range/node_modules/2/string.js +0 -37
- package/native/token-counter/node_modules/enforce-range/node_modules/2/test.js +0 -413
- package/native/token-counter/node_modules/enforce-range/package.json +0 -36
- package/native/token-counter/node_modules/enforce-range/readme.md +0 -53
- package/native/token-counter/node_modules/english-list/.travis.yml +0 -6
- package/native/token-counter/node_modules/english-list/LICENSE +0 -22
- package/native/token-counter/node_modules/english-list/README.md +0 -44
- package/native/token-counter/node_modules/english-list/index.js +0 -34
- package/native/token-counter/node_modules/english-list/package.json +0 -31
- package/native/token-counter/node_modules/english-list/test.log +0 -6
- package/native/token-counter/node_modules/errate/index.js +0 -19
- package/native/token-counter/node_modules/errate/license.txt +0 -21
- package/native/token-counter/node_modules/errate/package.json +0 -39
- package/native/token-counter/node_modules/errate/readme.md +0 -79
- package/native/token-counter/node_modules/ffn/index.js +0 -9
- package/native/token-counter/node_modules/ffn/license.txt +0 -21
- package/native/token-counter/node_modules/ffn/package.json +0 -34
- package/native/token-counter/node_modules/ffn/readme.md +0 -51
- package/native/token-counter/node_modules/get-own-property/index.js +0 -5
- package/native/token-counter/node_modules/get-own-property/license.txt +0 -21
- package/native/token-counter/node_modules/get-own-property/package.json +0 -31
- package/native/token-counter/node_modules/get-own-property/readme.md +0 -22
- package/native/token-counter/node_modules/has-duplicates/index.js +0 -11
- package/native/token-counter/node_modules/has-duplicates/license.txt +0 -21
- package/native/token-counter/node_modules/has-duplicates/package.json +0 -32
- package/native/token-counter/node_modules/has-duplicates/readme.md +0 -23
- package/native/token-counter/node_modules/has-duplicates/test.js +0 -30
- package/native/token-counter/node_modules/if-else-throw/index.js +0 -8
- package/native/token-counter/node_modules/if-else-throw/license.txt +0 -21
- package/native/token-counter/node_modules/if-else-throw/package.json +0 -37
- package/native/token-counter/node_modules/if-else-throw/readme.md +0 -32
- package/native/token-counter/node_modules/is-array-of-length/index.js +0 -7
- package/native/token-counter/node_modules/is-array-of-length/license.txt +0 -21
- package/native/token-counter/node_modules/is-array-of-length/package.json +0 -42
- package/native/token-counter/node_modules/is-array-of-length/readme.md +0 -41
- package/native/token-counter/node_modules/is-class-of/index.js +0 -7
- package/native/token-counter/node_modules/is-class-of/license.txt +0 -21
- package/native/token-counter/node_modules/is-class-of/package.json +0 -35
- package/native/token-counter/node_modules/is-class-of/readme.md +0 -57
- package/native/token-counter/node_modules/is-global-object/index.js +0 -6
- package/native/token-counter/node_modules/is-global-object/license.txt +0 -21
- package/native/token-counter/node_modules/is-global-object/package.json +0 -34
- package/native/token-counter/node_modules/is-global-object/readme.md +0 -22
- package/native/token-counter/node_modules/is-instance-of/index.js +0 -28
- package/native/token-counter/node_modules/is-instance-of/license.txt +0 -21
- package/native/token-counter/node_modules/is-instance-of/package.json +0 -44
- package/native/token-counter/node_modules/is-instance-of/readme.md +0 -55
- package/native/token-counter/node_modules/is-iterable/index.js +0 -5
- package/native/token-counter/node_modules/is-iterable/license +0 -21
- package/native/token-counter/node_modules/is-iterable/package.json +0 -30
- package/native/token-counter/node_modules/is-iterable/readme.md +0 -23
- package/native/token-counter/node_modules/is-nil/LICENSE +0 -21
- package/native/token-counter/node_modules/is-nil/README.md +0 -47
- package/native/token-counter/node_modules/is-nil/index.js +0 -6
- package/native/token-counter/node_modules/is-nil/package.json +0 -46
- package/native/token-counter/node_modules/is-obj/index.js +0 -5
- package/native/token-counter/node_modules/is-obj/license +0 -21
- package/native/token-counter/node_modules/is-obj/package.json +0 -33
- package/native/token-counter/node_modules/is-obj/readme.md +0 -34
- package/native/token-counter/node_modules/is-object/.eslintignore +0 -1
- package/native/token-counter/node_modules/is-object/.eslintrc +0 -5
- package/native/token-counter/node_modules/is-object/.nycrc +0 -13
- package/native/token-counter/node_modules/is-object/.testem.json +0 -14
- package/native/token-counter/node_modules/is-object/CHANGELOG.md +0 -121
- package/native/token-counter/node_modules/is-object/LICENSE +0 -19
- package/native/token-counter/node_modules/is-object/README.md +0 -48
- package/native/token-counter/node_modules/is-object/index.js +0 -5
- package/native/token-counter/node_modules/is-object/package.json +0 -78
- package/native/token-counter/node_modules/is-object/test/index.js +0 -44
- package/native/token-counter/node_modules/is-plain-object/LICENSE +0 -21
- package/native/token-counter/node_modules/is-plain-object/README.md +0 -104
- package/native/token-counter/node_modules/is-plain-object/index.d.ts +0 -5
- package/native/token-counter/node_modules/is-plain-object/index.js +0 -37
- package/native/token-counter/node_modules/is-plain-object/package.json +0 -79
- package/native/token-counter/node_modules/isobject/LICENSE +0 -21
- package/native/token-counter/node_modules/isobject/README.md +0 -122
- package/native/token-counter/node_modules/isobject/index.d.ts +0 -5
- package/native/token-counter/node_modules/isobject/index.js +0 -12
- package/native/token-counter/node_modules/isobject/package.json +0 -74
- package/native/token-counter/node_modules/lodash.set/LICENSE +0 -47
- package/native/token-counter/node_modules/lodash.set/README.md +0 -18
- package/native/token-counter/node_modules/lodash.set/index.js +0 -990
- package/native/token-counter/node_modules/lodash.set/package.json +0 -17
- package/native/token-counter/node_modules/longest-first/index.js +0 -3
- package/native/token-counter/node_modules/longest-first/license.txt +0 -21
- package/native/token-counter/node_modules/longest-first/package.json +0 -36
- package/native/token-counter/node_modules/longest-first/readme.md +0 -29
- package/native/token-counter/node_modules/m-o/index.js +0 -27
- package/native/token-counter/node_modules/m-o/license.txt +0 -21
- package/native/token-counter/node_modules/m-o/node_modules/new-object/index.js +0 -23
- package/native/token-counter/node_modules/m-o/node_modules/new-object/license.txt +0 -21
- package/native/token-counter/node_modules/m-o/node_modules/new-object/package.json +0 -40
- package/native/token-counter/node_modules/m-o/node_modules/new-object/readme.md +0 -55
- package/native/token-counter/node_modules/m-o/package.json +0 -45
- package/native/token-counter/node_modules/m-o/readme.md +0 -87
- package/native/token-counter/node_modules/map-iter/index.js +0 -6
- package/native/token-counter/node_modules/map-iter/license.txt +0 -21
- package/native/token-counter/node_modules/map-iter/package.json +0 -40
- package/native/token-counter/node_modules/map-iter/readme.md +0 -46
- package/native/token-counter/node_modules/new-object/index.js +0 -5
- package/native/token-counter/node_modules/new-object/license.txt +0 -21
- package/native/token-counter/node_modules/new-object/package.json +0 -49
- package/native/token-counter/node_modules/new-object/readme.md +0 -145
- package/native/token-counter/node_modules/ofn/index.js +0 -22
- package/native/token-counter/node_modules/ofn/license.txt +0 -21
- package/native/token-counter/node_modules/ofn/package.json +0 -40
- package/native/token-counter/node_modules/ofn/readme.md +0 -63
- package/native/token-counter/node_modules/otherwise/index.js +0 -11
- package/native/token-counter/node_modules/otherwise/license.txt +0 -21
- package/native/token-counter/node_modules/otherwise/package.json +0 -38
- package/native/token-counter/node_modules/otherwise/readme.md +0 -29
- package/native/token-counter/node_modules/parser-factory/index.js +0 -138
- package/native/token-counter/node_modules/parser-factory/license.txt +0 -21
- package/native/token-counter/node_modules/parser-factory/node_modules/arrify/index.d.ts +0 -38
- package/native/token-counter/node_modules/parser-factory/node_modules/arrify/index.js +0 -23
- package/native/token-counter/node_modules/parser-factory/node_modules/arrify/license +0 -9
- package/native/token-counter/node_modules/parser-factory/node_modules/arrify/package.json +0 -35
- package/native/token-counter/node_modules/parser-factory/node_modules/arrify/readme.md +0 -39
- package/native/token-counter/node_modules/parser-factory/package.json +0 -38
- package/native/token-counter/node_modules/parser-factory/readme.md +0 -15
- package/native/token-counter/node_modules/pfn/index.js +0 -5
- package/native/token-counter/node_modules/pfn/license.txt +0 -21
- package/native/token-counter/node_modules/pfn/package.json +0 -41
- package/native/token-counter/node_modules/pfn/readme.md +0 -111
- package/native/token-counter/node_modules/pfn/strict.js +0 -8
- package/native/token-counter/node_modules/plainify/index.js +0 -5
- package/native/token-counter/node_modules/plainify/license.txt +0 -21
- package/native/token-counter/node_modules/plainify/package.json +0 -36
- package/native/token-counter/node_modules/plainify/readme.md +0 -47
- package/native/token-counter/node_modules/possible-function/changelog.md +0 -7
- package/native/token-counter/node_modules/possible-function/index.js +0 -43
- package/native/token-counter/node_modules/possible-function/license.txt +0 -21
- package/native/token-counter/node_modules/possible-function/package.json +0 -34
- package/native/token-counter/node_modules/possible-function/readme.md +0 -77
- package/native/token-counter/node_modules/possible-function/test.js +0 -32
- package/native/token-counter/node_modules/qfn/index.js +0 -11
- package/native/token-counter/node_modules/qfn/license.txt +0 -21
- package/native/token-counter/node_modules/qfn/package.json +0 -40
- package/native/token-counter/node_modules/qfn/readme.md +0 -45
- package/native/token-counter/node_modules/roadblock/index.js +0 -3
- package/native/token-counter/node_modules/roadblock/license.txt +0 -21
- package/native/token-counter/node_modules/roadblock/package.json +0 -40
- package/native/token-counter/node_modules/roadblock/readme.md +0 -59
- package/native/token-counter/node_modules/round-to/index.d.ts +0 -56
- package/native/token-counter/node_modules/round-to/index.js +0 -37
- package/native/token-counter/node_modules/round-to/license +0 -9
- package/native/token-counter/node_modules/round-to/package.json +0 -38
- package/native/token-counter/node_modules/round-to/readme.md +0 -71
- package/native/token-counter/node_modules/rtrim-array/index.js +0 -10
- package/native/token-counter/node_modules/rtrim-array/license.txt +0 -21
- package/native/token-counter/node_modules/rtrim-array/package.json +0 -41
- package/native/token-counter/node_modules/rtrim-array/readme.md +0 -75
- package/native/token-counter/node_modules/sbo/index.js +0 -25
- package/native/token-counter/node_modules/sbo/license.txt +0 -21
- package/native/token-counter/node_modules/sbo/package.json +0 -50
- package/native/token-counter/node_modules/sbo/readme.md +0 -105
- package/native/token-counter/node_modules/sorp/index.js +0 -3
- package/native/token-counter/node_modules/sorp/license.txt +0 -21
- package/native/token-counter/node_modules/sorp/package.json +0 -34
- package/native/token-counter/node_modules/sorp/readme.md +0 -25
- package/native/token-counter/node_modules/trim-call/index.js +0 -6
- package/native/token-counter/node_modules/trim-call/license.txt +0 -21
- package/native/token-counter/node_modules/trim-call/package.json +0 -40
- package/native/token-counter/node_modules/trim-call/readme.md +0 -80
- package/native/token-counter/node_modules/type-error/LICENSE +0 -21
- package/native/token-counter/node_modules/type-error/README.md +0 -24
- package/native/token-counter/node_modules/type-error/index.js +0 -35
- package/native/token-counter/node_modules/type-error/package.json +0 -11
- package/native/token-counter/node_modules/vfn/index.js +0 -21
- package/native/token-counter/node_modules/vfn/license.txt +0 -21
- package/native/token-counter/node_modules/vfn/package.json +0 -40
- package/native/token-counter/node_modules/vfn/readme.md +0 -81
- package/native/token-counter/node_modules/wfn/index.js +0 -43
- package/native/token-counter/node_modules/wfn/license.txt +0 -21
- package/native/token-counter/node_modules/wfn/package.json +0 -38
- package/native/token-counter/node_modules/wfn/readme.md +0 -81
- package/native/token-counter/package-lock.json +0 -578
- package/native/token-counter/package.json +0 -21
- package/native/token-counter/token-counter.linux-x64-gnu.node +0 -0
package/dist/tools/Browser.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { launchPersistentContext, ensureBinary } from 'cloakbrowser';
|
|
2
2
|
import { homedir } from 'os';
|
|
3
3
|
import { join } from 'path';
|
|
4
|
-
import { readdirSync, readFileSync, unlinkSync } from 'fs';
|
|
5
4
|
import { loadConfig } from '../agent/Config.js';
|
|
5
|
+
import { visionClassify, readFileBase64, findGridTiles, humanClick, humanMove, humanHold, warmupBehavior, solveCaptchaGrid, autoSolveCaptcha, analyzeImageChallenge, _lastGridAnalyzeTime, bezierPoint, easeInOut, } from './captcha/index.js';
|
|
6
6
|
function ok(msg, details) {
|
|
7
7
|
const lines = [`[OK] ${msg}`];
|
|
8
8
|
if (details)
|
|
@@ -33,323 +33,6 @@ async function autoScreenshot(p, label) {
|
|
|
33
33
|
catch { }
|
|
34
34
|
return path;
|
|
35
35
|
}
|
|
36
|
-
// ─── Vision-Based Captcha Auto-Solve ──────────────────────────────────────
|
|
37
|
-
let _lastGridAnalyzeTime = 0;
|
|
38
|
-
function readFileBase64(path) {
|
|
39
|
-
return readFileSync(path).toString('base64');
|
|
40
|
-
}
|
|
41
|
-
async function visionClassify(imageBase64, prompt) {
|
|
42
|
-
const config = loadConfig();
|
|
43
|
-
const visionModel = config.visionModel || config.model || 'gpt-4o';
|
|
44
|
-
const visionBaseUrl = config.visionBaseUrl || config.baseUrl;
|
|
45
|
-
const visionApiKey = config.visionApiKey || config.apiKey;
|
|
46
|
-
const body = {
|
|
47
|
-
model: visionModel,
|
|
48
|
-
messages: [{
|
|
49
|
-
role: 'user',
|
|
50
|
-
content: [
|
|
51
|
-
{ type: 'text', text: prompt },
|
|
52
|
-
{ type: 'image_url', image_url: { url: `data:image/png;base64,${imageBase64}` } },
|
|
53
|
-
],
|
|
54
|
-
}],
|
|
55
|
-
max_tokens: 100,
|
|
56
|
-
};
|
|
57
|
-
const controller = new AbortController();
|
|
58
|
-
const fetchTimeout = setTimeout(() => controller.abort(), 15_000);
|
|
59
|
-
try {
|
|
60
|
-
const resp = await fetch(`${visionBaseUrl}/chat/completions`, {
|
|
61
|
-
method: 'POST',
|
|
62
|
-
headers: {
|
|
63
|
-
'Content-Type': 'application/json',
|
|
64
|
-
...(visionApiKey ? { Authorization: `Bearer ${visionApiKey}` } : {}),
|
|
65
|
-
},
|
|
66
|
-
body: JSON.stringify(body),
|
|
67
|
-
signal: controller.signal,
|
|
68
|
-
});
|
|
69
|
-
if (!resp.ok)
|
|
70
|
-
throw new Error(`Vision API error: ${resp.status}`);
|
|
71
|
-
const text = await resp.text();
|
|
72
|
-
if (text.includes('data: ')) {
|
|
73
|
-
let content = '';
|
|
74
|
-
for (const line of text.split('\n')) {
|
|
75
|
-
if (line.startsWith('data: ') && line.trim() !== 'data: [DONE]') {
|
|
76
|
-
try {
|
|
77
|
-
const ev = JSON.parse(line.slice(6));
|
|
78
|
-
const delta = ev.choices?.[0]?.delta;
|
|
79
|
-
if (delta?.content)
|
|
80
|
-
content += delta.content;
|
|
81
|
-
if (delta?.text)
|
|
82
|
-
content += delta.text;
|
|
83
|
-
if (ev.choices?.[0]?.message?.content)
|
|
84
|
-
content += ev.choices[0].message.content;
|
|
85
|
-
}
|
|
86
|
-
catch { }
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return content.trim();
|
|
90
|
-
}
|
|
91
|
-
const json = JSON.parse(text);
|
|
92
|
-
return (json.choices?.[0]?.message?.content || '').trim();
|
|
93
|
-
}
|
|
94
|
-
finally {
|
|
95
|
-
clearTimeout(fetchTimeout);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
async function solveCaptchaGrid(page, frame, provider) {
|
|
99
|
-
const results = [];
|
|
100
|
-
const isRecaptcha = provider === 'recaptcha';
|
|
101
|
-
const _t0 = Date.now();
|
|
102
|
-
const _elapsed = () => ((Date.now() - _t0) / 1000).toFixed(1);
|
|
103
|
-
let instruction = '';
|
|
104
|
-
try {
|
|
105
|
-
const instrEl = frame.locator('.rc-imageselect-instructions, .prompt-text, .prompt-text-h, .geetest_tip_content, .mtcaptcha-label');
|
|
106
|
-
if (await instrEl.count() > 0) {
|
|
107
|
-
instruction = (await instrEl.first().textContent() || '').trim();
|
|
108
|
-
}
|
|
109
|
-
if (!instruction) {
|
|
110
|
-
const strongText = frame.locator('strong').first();
|
|
111
|
-
if (await strongText.count() > 0)
|
|
112
|
-
instruction = (await strongText.textContent() || '').trim();
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
catch { }
|
|
116
|
-
if (!instruction) {
|
|
117
|
-
results.push('[WARN] Could not extract captcha instruction, cannot auto-solve');
|
|
118
|
-
return results.join('\n');
|
|
119
|
-
}
|
|
120
|
-
results.push(`Auto-solving: "${instruction}"`);
|
|
121
|
-
results.push(`[timing] instruction: ${_elapsed()}s`);
|
|
122
|
-
try {
|
|
123
|
-
const home = homedir();
|
|
124
|
-
for (const f of readdirSync(home)) {
|
|
125
|
-
if (/^\.aurix-tile-(\d+|after-\d+)\.png$/.test(f)) {
|
|
126
|
-
try {
|
|
127
|
-
unlinkSync(join(home, f));
|
|
128
|
-
}
|
|
129
|
-
catch { }
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
catch { }
|
|
134
|
-
const tiles = await findGridTiles(frame, provider);
|
|
135
|
-
const gridScreenshotPath = join(homedir(), '.aurix-captcha-grid.png');
|
|
136
|
-
try {
|
|
137
|
-
const gridEl = frame.locator('.rc-imageselect-table-33, .rc-imageselect-table-44, .task, .challenge-view, table').first();
|
|
138
|
-
if (await gridEl.count() > 0)
|
|
139
|
-
await gridEl.screenshot({ path: gridScreenshotPath });
|
|
140
|
-
else
|
|
141
|
-
await frame.locator('body').screenshot({ path: gridScreenshotPath });
|
|
142
|
-
}
|
|
143
|
-
catch {
|
|
144
|
-
try {
|
|
145
|
-
await page.screenshot({ path: gridScreenshotPath });
|
|
146
|
-
}
|
|
147
|
-
catch { }
|
|
148
|
-
}
|
|
149
|
-
results.push(`[timing] grid screenshot: ${_elapsed()}s (${tiles.length} tiles)`);
|
|
150
|
-
const classifyPrompt = `Look at this captcha grid image. The instruction is: "${instruction}". Which tile images match this instruction? Reply with ONLY the 0-based indices separated by commas (e.g. "0,3,5"). If none match, reply "none".`;
|
|
151
|
-
let matchedIndices = [];
|
|
152
|
-
try {
|
|
153
|
-
const gridBase64 = readFileBase64(gridScreenshotPath);
|
|
154
|
-
const response = await visionClassify(gridBase64, classifyPrompt);
|
|
155
|
-
results.push(`Vision model: "${response}"`);
|
|
156
|
-
if (response.toLowerCase().includes('none')) {
|
|
157
|
-
results.push('Vision: no matching tiles, clicking verify directly');
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
matchedIndices = response.split(',')
|
|
161
|
-
.map(s => parseInt(s.trim()))
|
|
162
|
-
.filter(n => !isNaN(n) && n >= 0 && n < tiles.length);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
catch (e) {
|
|
166
|
-
results.push(`[WARN] Vision model failed: ${e.message}`);
|
|
167
|
-
results.push('Auto-solve requires a vision-capable model. Falling back to manual mode.');
|
|
168
|
-
results.push('Use "captcha-grid" to see tiles and "click-tile" to select them manually.');
|
|
169
|
-
return results.join('\n');
|
|
170
|
-
}
|
|
171
|
-
if (matchedIndices.length === 0) {
|
|
172
|
-
results.push('No matching tiles found, attempting verify directly');
|
|
173
|
-
}
|
|
174
|
-
results.push(`[timing] before clicks: ${_elapsed()}s, clicking ${matchedIndices.length} tiles`);
|
|
175
|
-
for (const idx of matchedIndices) {
|
|
176
|
-
try {
|
|
177
|
-
if (idx >= tiles.length)
|
|
178
|
-
continue;
|
|
179
|
-
await tiles[idx].click({ force: true, timeout: 3000 });
|
|
180
|
-
await page.waitForTimeout(200 + Math.random() * 200);
|
|
181
|
-
results.push(` Clicked tile ${idx}`);
|
|
182
|
-
}
|
|
183
|
-
catch (e) {
|
|
184
|
-
try {
|
|
185
|
-
const currentTiles = await findGridTiles(frame, provider);
|
|
186
|
-
if (idx < currentTiles.length) {
|
|
187
|
-
await currentTiles[idx].click({ force: true, timeout: 3000 });
|
|
188
|
-
await page.waitForTimeout(200 + Math.random() * 200);
|
|
189
|
-
results.push(` Clicked tile ${idx} (re-fetched)`);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
catch (e2) {
|
|
193
|
-
results.push(` Failed to click tile ${idx}: ${e2.message}`);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
if (isRecaptcha && matchedIndices.length > 0) {
|
|
198
|
-
await page.waitForTimeout(800 + Math.random() * 400);
|
|
199
|
-
}
|
|
200
|
-
results.push(`Clicking verify... [${_elapsed()}s]`);
|
|
201
|
-
try {
|
|
202
|
-
let verifyBtn = frame.locator('#recaptcha-verify-button, .rc-button-submit, .button-submit, [id*="verify"]');
|
|
203
|
-
if (await verifyBtn.count() === 0) {
|
|
204
|
-
verifyBtn = frame.locator('button:has-text("Verify"), button:has-text("Next"), button:has-text("Submit")');
|
|
205
|
-
}
|
|
206
|
-
if (await verifyBtn.count() > 0) {
|
|
207
|
-
await verifyBtn.click({ force: true, timeout: 5000 });
|
|
208
|
-
await page.waitForTimeout(2000);
|
|
209
|
-
const errorText = await frame.locator('.rc-imageselect-incorrect-response, .error-message, .incorrect').count();
|
|
210
|
-
if (errorText > 0) {
|
|
211
|
-
results.push('Verification failed, challenge will retry');
|
|
212
|
-
return results.join('\n');
|
|
213
|
-
}
|
|
214
|
-
const newChallenge = await frame.locator('.rc-imageselect-instructions, .prompt-text').count();
|
|
215
|
-
if (newChallenge > 0) {
|
|
216
|
-
const newInstr = (await frame.locator('.rc-imageselect-instructions, .prompt-text').first().textContent() || '').trim();
|
|
217
|
-
if (newInstr !== instruction) {
|
|
218
|
-
results.push(`New challenge appeared: "${newInstr}"`);
|
|
219
|
-
return results.join('\n');
|
|
220
|
-
}
|
|
221
|
-
results.push('Same challenge still present');
|
|
222
|
-
return results.join('\n');
|
|
223
|
-
}
|
|
224
|
-
const verifyResultPath = join(homedir(), '.aurix-captcha-verify-result.png');
|
|
225
|
-
await page.screenshot({ path: verifyResultPath }).catch(() => { });
|
|
226
|
-
results.push(`[OK] Captcha solved! Screenshot: ${verifyResultPath}`);
|
|
227
|
-
return results.join('\n');
|
|
228
|
-
}
|
|
229
|
-
else {
|
|
230
|
-
results.push('[WARN] No verify button found');
|
|
231
|
-
return results.join('\n');
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
catch (e) {
|
|
235
|
-
results.push(`Verify failed: ${e.message}`);
|
|
236
|
-
return results.join('\n');
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
// ─── Human-Like Mouse Utilities ────────────────────────────────────────────
|
|
240
|
-
function bezierPoint(t, points) {
|
|
241
|
-
if (points.length === 1)
|
|
242
|
-
return points[0];
|
|
243
|
-
const next = [];
|
|
244
|
-
for (let i = 0; i < points.length - 1; i++) {
|
|
245
|
-
next.push([
|
|
246
|
-
points[i][0] + (points[i + 1][0] - points[i][0]) * t,
|
|
247
|
-
points[i][1] + (points[i + 1][1] - points[i][1]) * t,
|
|
248
|
-
]);
|
|
249
|
-
}
|
|
250
|
-
return bezierPoint(t, next);
|
|
251
|
-
}
|
|
252
|
-
function easeInOut(t) {
|
|
253
|
-
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
|
254
|
-
}
|
|
255
|
-
async function humanMove(x, y, page) {
|
|
256
|
-
const mouse = page.mouse;
|
|
257
|
-
const vp = page.viewportSize() || { width: 1280, height: 720 };
|
|
258
|
-
// Start from a random position if we don't know current pos
|
|
259
|
-
const startX = Math.random() * vp.width * 0.3;
|
|
260
|
-
const startY = Math.random() * vp.height * 0.3;
|
|
261
|
-
// Generate 2-4 control points for bezier curve
|
|
262
|
-
const numControls = 2 + Math.floor(Math.random() * 3);
|
|
263
|
-
const controlPoints = [[startX, startY]];
|
|
264
|
-
for (let i = 0; i < numControls; i++) {
|
|
265
|
-
const frac = (i + 1) / (numControls + 1);
|
|
266
|
-
const cx = startX + (x - startX) * frac + (Math.random() - 0.5) * 80;
|
|
267
|
-
const cy = startY + (y - startY) * frac + (Math.random() - 0.5) * 60;
|
|
268
|
-
controlPoints.push([cx, cy]);
|
|
269
|
-
}
|
|
270
|
-
controlPoints.push([x, y]);
|
|
271
|
-
// Step through the curve with eased timing
|
|
272
|
-
const totalSteps = 25 + Math.floor(Math.random() * 20);
|
|
273
|
-
for (let step = 0; step <= totalSteps; step++) {
|
|
274
|
-
const rawT = step / totalSteps;
|
|
275
|
-
const t = easeInOut(rawT);
|
|
276
|
-
const [px, py] = bezierPoint(t, controlPoints);
|
|
277
|
-
// Sine-wave micro-tremor (not uniform random)
|
|
278
|
-
const tremor = Math.sin(step * 0.3 + Math.random() * 0.5) * 0.4;
|
|
279
|
-
const tremorY = Math.cos(step * 0.25 + Math.random() * 0.5) * 0.3;
|
|
280
|
-
await mouse.move(px + tremor, py + tremorY);
|
|
281
|
-
// Variable step delay: faster in middle, slower at start/end
|
|
282
|
-
const speedFactor = 1 - Math.abs(rawT - 0.5) * 2;
|
|
283
|
-
const delay = 8 + Math.random() * 12 + speedFactor * 5;
|
|
284
|
-
await page.waitForTimeout(delay);
|
|
285
|
-
}
|
|
286
|
-
// Occasional overshoot + correction
|
|
287
|
-
if (Math.random() > 0.6) {
|
|
288
|
-
const overX = x + (Math.random() - 0.5) * 8;
|
|
289
|
-
const overY = y + (Math.random() - 0.5) * 8;
|
|
290
|
-
await mouse.move(overX, overY);
|
|
291
|
-
await page.waitForTimeout(30 + Math.random() * 40);
|
|
292
|
-
await mouse.move(x, y);
|
|
293
|
-
await page.waitForTimeout(20 + Math.random() * 30);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
let lastWarmupTime = 0;
|
|
297
|
-
async function warmupBehavior(page) {
|
|
298
|
-
const now = Date.now();
|
|
299
|
-
if (now - lastWarmupTime < 30000)
|
|
300
|
-
return;
|
|
301
|
-
lastWarmupTime = now;
|
|
302
|
-
const vp = page.viewportSize() || { width: 1280, height: 720 };
|
|
303
|
-
const spots = 1 + Math.floor(Math.random() * 2);
|
|
304
|
-
for (let i = 0; i < spots; i++) {
|
|
305
|
-
const rx = Math.random() * vp.width;
|
|
306
|
-
const ry = Math.random() * vp.height;
|
|
307
|
-
await humanMove(rx, ry, page);
|
|
308
|
-
await page.waitForTimeout(150 + Math.random() * 300);
|
|
309
|
-
}
|
|
310
|
-
if (Math.random() > 0.5) {
|
|
311
|
-
const scrollDelta = Math.floor(Math.random() * 150) - 75;
|
|
312
|
-
await page.mouse.wheel(0, scrollDelta);
|
|
313
|
-
await page.waitForTimeout(200 + Math.random() * 300);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
async function humanHold(x, y, duration, page) {
|
|
317
|
-
const mouse = page.mouse;
|
|
318
|
-
const holdSteps = Math.floor(duration / 80);
|
|
319
|
-
const breathFreq = 0.15 + Math.random() * 0.1;
|
|
320
|
-
const breathAmpX = 0.3 + Math.random() * 0.4;
|
|
321
|
-
const breathAmpY = 0.2 + Math.random() * 0.3;
|
|
322
|
-
await mouse.down();
|
|
323
|
-
for (let i = 0; i < holdSteps; i++) {
|
|
324
|
-
// Sine-wave breathing movement (natural hand tremor)
|
|
325
|
-
const breathX = Math.sin(i * breathFreq) * breathAmpX;
|
|
326
|
-
const breathY = Math.cos(i * breathFreq * 0.7) * breathAmpY;
|
|
327
|
-
// Occasional micro-adjustment
|
|
328
|
-
const adjX = Math.random() > 0.95 ? (Math.random() - 0.5) * 2 : 0;
|
|
329
|
-
const adjY = Math.random() > 0.95 ? (Math.random() - 0.5) * 2 : 0;
|
|
330
|
-
await mouse.move(x + breathX + adjX, y + breathY + adjY);
|
|
331
|
-
await page.waitForTimeout(60 + Math.random() * 40);
|
|
332
|
-
}
|
|
333
|
-
// Release with slight upward drift
|
|
334
|
-
await mouse.move(x + (Math.random() - 0.5) * 3, y - 1 - Math.random() * 2);
|
|
335
|
-
await page.waitForTimeout(30 + Math.random() * 50);
|
|
336
|
-
await mouse.up();
|
|
337
|
-
}
|
|
338
|
-
async function humanClick(locator, page) {
|
|
339
|
-
const box = await locator.first().boundingBox();
|
|
340
|
-
if (box) {
|
|
341
|
-
const clickX = box.x + box.width * (0.3 + Math.random() * 0.4);
|
|
342
|
-
const clickY = box.y + box.height * (0.3 + Math.random() * 0.4);
|
|
343
|
-
await humanMove(clickX, clickY, page);
|
|
344
|
-
await page.waitForTimeout(60 + Math.random() * 100);
|
|
345
|
-
await page.mouse.down();
|
|
346
|
-
await page.waitForTimeout(50 + Math.random() * 80);
|
|
347
|
-
await page.mouse.up();
|
|
348
|
-
}
|
|
349
|
-
else {
|
|
350
|
-
await locator.first().click({ force: true });
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
36
|
const sessions = new Map();
|
|
354
37
|
const sessionProxies = new Map();
|
|
355
38
|
const MAX_BROWSER_SESSIONS = 3;
|
|
@@ -697,283 +380,6 @@ async function resolveLocator(p, target) {
|
|
|
697
380
|
}
|
|
698
381
|
return locator;
|
|
699
382
|
}
|
|
700
|
-
async function autoSolveCaptcha(p) {
|
|
701
|
-
const results = [];
|
|
702
|
-
const frames = p.frames();
|
|
703
|
-
let recaptchaAnchor = null;
|
|
704
|
-
let recaptchaBframe = null;
|
|
705
|
-
let geetestSlider = null;
|
|
706
|
-
let turnstileFrame = null;
|
|
707
|
-
for (const frame of frames) {
|
|
708
|
-
const url = frame.url();
|
|
709
|
-
if (url.includes('/recaptcha/') && url.includes('/anchor'))
|
|
710
|
-
recaptchaAnchor = frame;
|
|
711
|
-
if (url.includes('/recaptcha/') && url.includes('/bframe'))
|
|
712
|
-
recaptchaBframe = frame;
|
|
713
|
-
if (url.includes('geetest.com') || url.includes('captcha.com')) {
|
|
714
|
-
const hasSlider = await frame.locator('.geetest_slider_button, .geetest_slider').count();
|
|
715
|
-
if (hasSlider > 0)
|
|
716
|
-
geetestSlider = frame;
|
|
717
|
-
}
|
|
718
|
-
if (url.includes('challenges.cloudflare') || url.includes('turnstile'))
|
|
719
|
-
turnstileFrame = frame;
|
|
720
|
-
}
|
|
721
|
-
if (turnstileFrame) {
|
|
722
|
-
try {
|
|
723
|
-
const checkbox = turnstileFrame.locator('input[type="checkbox"], .cf-turnstile, [role="checkbox"]').first();
|
|
724
|
-
if (await checkbox.count() > 0) {
|
|
725
|
-
await checkbox.click({ timeout: 5000 });
|
|
726
|
-
await p.waitForTimeout(3000);
|
|
727
|
-
// Don't claim "solved" — verify the widget actually reported success.
|
|
728
|
-
const tsOk = await turnstileFrame.locator('input[type="hidden"][name="cf-turnstile-response"], [data-state="success"], .success').count().catch(() => 0);
|
|
729
|
-
const tsError = await turnstileFrame.locator('.error, [data-state="error"], [data-state="failed"]').count().catch(() => 0);
|
|
730
|
-
if (tsOk > 0)
|
|
731
|
-
results.push('Turnstile: checkbox clicked, widget reports success');
|
|
732
|
-
else if (tsError > 0)
|
|
733
|
-
results.push('Turnstile: checkbox clicked but widget shows an error — may need a screenshot to inspect');
|
|
734
|
-
else
|
|
735
|
-
results.push('Turnstile: checkbox clicked, outcome unconfirmed — take a screenshot to verify the page advanced before submitting');
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
catch (e) {
|
|
739
|
-
results.push(`Turnstile: auto-click attempted (${e.message?.slice(0, 80)})`);
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
if (recaptchaAnchor && !recaptchaBframe) {
|
|
743
|
-
try {
|
|
744
|
-
const checkbox = recaptchaAnchor.locator('#recaptcha-anchor, .recaptcha-checkbox-border, .rc-anchor-checkbox').first();
|
|
745
|
-
if (await checkbox.count() > 0) {
|
|
746
|
-
await checkbox.click({ timeout: 5000 });
|
|
747
|
-
await p.waitForTimeout(2000);
|
|
748
|
-
// The checkbox click may pass instantly OR pop an image challenge.
|
|
749
|
-
// Report which actually happened instead of claiming success.
|
|
750
|
-
const checked = await recaptchaAnchor.locator('.recaptcha-checkbox-checked, .rc-anchor-checkbox-checked').count().catch(() => 0);
|
|
751
|
-
const challengeOpened = p.frames().some((f) => f.url().includes('/recaptcha/') && f.url().includes('/bframe'));
|
|
752
|
-
if (checked > 0)
|
|
753
|
-
results.push('reCAPTCHA: checkbox verified (checked) — no image challenge');
|
|
754
|
-
else if (challengeOpened)
|
|
755
|
-
results.push('reCAPTCHA: checkbox clicked, image challenge appeared — use captcha-grid to solve it');
|
|
756
|
-
else
|
|
757
|
-
results.push('reCAPTCHA: checkbox clicked, outcome unconfirmed — take a screenshot to verify before submitting');
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
catch (e) {
|
|
761
|
-
results.push(`reCAPTCHA checkbox: auto-click attempted (${e.message?.slice(0, 80)})`);
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
if (geetestSlider) {
|
|
765
|
-
try {
|
|
766
|
-
const sliderInfo = await geetestSlider.evaluate(() => {
|
|
767
|
-
const info = {};
|
|
768
|
-
const cut = document.querySelector('.geetest_cut, .geetest_piece_bg, [class*="geetest_cut"], [class*="slider_cut"]');
|
|
769
|
-
if (cut) {
|
|
770
|
-
const cutRect = cut.getBoundingClientRect();
|
|
771
|
-
const style = window.getComputedStyle(cut);
|
|
772
|
-
info.cut = { left: cutRect.left, width: cutRect.width, styleLeft: parseFloat(style.left) || null, transform: style.transform || null };
|
|
773
|
-
}
|
|
774
|
-
const bg = document.querySelector('.geetest_canvas_bg, .geetest_bg, [class*="geetest_canvas"], canvas[class*="bg"]');
|
|
775
|
-
if (bg)
|
|
776
|
-
info.bg = { left: bg.getBoundingClientRect().left, width: bg.getBoundingClientRect().width };
|
|
777
|
-
const piece = document.querySelector('.geetest_piece, [class*="slider_piece"]');
|
|
778
|
-
if (piece)
|
|
779
|
-
info.piece = { width: piece.getBoundingClientRect().width };
|
|
780
|
-
const slider = document.querySelector('.geetest_slider_button, [class*="slider_button"]');
|
|
781
|
-
if (slider) {
|
|
782
|
-
const r = slider.getBoundingClientRect();
|
|
783
|
-
info.slider = { left: r.left, width: r.width, centerX: r.left + r.width / 2, centerY: r.top + r.height / 2 };
|
|
784
|
-
}
|
|
785
|
-
return info;
|
|
786
|
-
});
|
|
787
|
-
let gapOffset = null;
|
|
788
|
-
if (sliderInfo.cut && sliderInfo.bg) {
|
|
789
|
-
if (sliderInfo.cut.styleLeft && sliderInfo.cut.styleLeft > 0)
|
|
790
|
-
gapOffset = Math.round(sliderInfo.cut.styleLeft);
|
|
791
|
-
else
|
|
792
|
-
gapOffset = Math.round(sliderInfo.cut.left - sliderInfo.bg.left);
|
|
793
|
-
}
|
|
794
|
-
if (gapOffset === null && sliderInfo.cut?.transform && sliderInfo.cut.transform !== 'none') {
|
|
795
|
-
const match = sliderInfo.cut.transform.match(/matrix\(.*?,\s*([\d.]+)/);
|
|
796
|
-
if (match)
|
|
797
|
-
gapOffset = Math.round(parseFloat(match[1]));
|
|
798
|
-
}
|
|
799
|
-
if (gapOffset !== null && sliderInfo.slider) {
|
|
800
|
-
const pieceHalf = Math.round((sliderInfo.piece?.width || 44) / 2);
|
|
801
|
-
const dragDistance = gapOffset - pieceHalf;
|
|
802
|
-
const startX = sliderInfo.slider.centerX;
|
|
803
|
-
const startY = sliderInfo.slider.centerY;
|
|
804
|
-
const endX = startX + dragDistance;
|
|
805
|
-
await p.mouse.move(startX, startY);
|
|
806
|
-
await p.waitForTimeout(150);
|
|
807
|
-
await p.mouse.down();
|
|
808
|
-
await p.waitForTimeout(200);
|
|
809
|
-
const steps = 18 + Math.floor(Math.random() * 8);
|
|
810
|
-
for (let i = 1; i <= steps; i++) {
|
|
811
|
-
const progress = i / steps;
|
|
812
|
-
const eased = progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2;
|
|
813
|
-
const x = startX + dragDistance * eased + (Math.random() - 0.5) * 2;
|
|
814
|
-
const y = startY + (Math.random() - 0.5) * 2;
|
|
815
|
-
await p.mouse.move(x, y);
|
|
816
|
-
await p.waitForTimeout(10 + Math.random() * 20);
|
|
817
|
-
}
|
|
818
|
-
await p.mouse.move(endX, startY);
|
|
819
|
-
await p.waitForTimeout(150);
|
|
820
|
-
await p.mouse.up();
|
|
821
|
-
await p.waitForTimeout(2000);
|
|
822
|
-
results.push(`GeeTest: slider dragged ${dragDistance}px — outcome unconfirmed, take a screenshot to verify the gap was matched`);
|
|
823
|
-
}
|
|
824
|
-
else {
|
|
825
|
-
results.push('GeeTest slider detected but gap position could not be auto-detected');
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
catch (e) {
|
|
829
|
-
results.push(`GeeTest slider: auto-solve attempted (${e.message?.slice(0, 80)})`);
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
if (recaptchaBframe) {
|
|
833
|
-
const gridResult = await analyzeImageChallenge(p, recaptchaBframe, 'recaptcha');
|
|
834
|
-
results.push('reCAPTCHA image challenge detected — grid analysis:');
|
|
835
|
-
results.push(gridResult);
|
|
836
|
-
}
|
|
837
|
-
const funcaptchaFrame = frames.find(f => f.url().includes('funcaptcha') || f.url().includes('arkoselabs'));
|
|
838
|
-
if (funcaptchaFrame) {
|
|
839
|
-
results.push('FunCaptcha detected — screenshotting puzzle...');
|
|
840
|
-
try {
|
|
841
|
-
const fcScreenshotPath = join(homedir(), '.aurix-funcaptcha-puzzle.png');
|
|
842
|
-
await funcaptchaFrame.locator('body').screenshot({ path: fcScreenshotPath }).catch(() => p.screenshot({ path: fcScreenshotPath }));
|
|
843
|
-
results.push(`Puzzle screenshot: ${fcScreenshotPath}`);
|
|
844
|
-
results.push('Analyze the puzzle image and determine the correct answer, then use click/evaluate to solve it.');
|
|
845
|
-
}
|
|
846
|
-
catch {
|
|
847
|
-
results.push('REQUIRES_VISION: FunCaptcha detected — needs image analysis to solve');
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
return results;
|
|
851
|
-
}
|
|
852
|
-
async function findGridTiles(frame, provider) {
|
|
853
|
-
switch (provider) {
|
|
854
|
-
case 'recaptcha': {
|
|
855
|
-
const tiles33 = frame.locator('.rc-imageselect-table-33 td, .rc-image-tile-33 td');
|
|
856
|
-
if (await tiles33.count() > 0)
|
|
857
|
-
return tiles33.all();
|
|
858
|
-
const tiles44 = frame.locator('.rc-imageselect-table-44 td, .rc-image-tile-44 td');
|
|
859
|
-
if (await tiles44.count() > 0)
|
|
860
|
-
return tiles44.all();
|
|
861
|
-
const generic = frame.locator('table td');
|
|
862
|
-
if (await generic.count() > 0)
|
|
863
|
-
return generic.all();
|
|
864
|
-
return [];
|
|
865
|
-
}
|
|
866
|
-
case 'hcaptcha': {
|
|
867
|
-
const tiles = frame.locator('.task-image, .image, .task .answer');
|
|
868
|
-
if (await tiles.count() > 0)
|
|
869
|
-
return tiles.all();
|
|
870
|
-
return [];
|
|
871
|
-
}
|
|
872
|
-
case 'mtcaptcha':
|
|
873
|
-
case 'geetest': {
|
|
874
|
-
const items = frame.locator('.geetest_item_wrap, .geetest_ques_tips img, .mtcaptcha-item');
|
|
875
|
-
if (await items.count() > 0)
|
|
876
|
-
return items.all();
|
|
877
|
-
return [];
|
|
878
|
-
}
|
|
879
|
-
default: {
|
|
880
|
-
const tiles = frame.locator('.task-image, .rc-imageselect-table-33 td, .rc-imageselect-table-44 td, table td');
|
|
881
|
-
if (await tiles.count() > 0)
|
|
882
|
-
return tiles.all();
|
|
883
|
-
return [];
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
async function analyzeImageChallenge(page, frame, provider) {
|
|
888
|
-
const results = [];
|
|
889
|
-
let instruction = '';
|
|
890
|
-
try {
|
|
891
|
-
const instrEl = frame.locator('.rc-imageselect-instructions, .prompt-text, .prompt-text-h, .geetest_tip_content, .mtcaptcha-label');
|
|
892
|
-
if (await instrEl.count() > 0) {
|
|
893
|
-
instruction = (await instrEl.first().textContent()) || '';
|
|
894
|
-
instruction = instruction.trim();
|
|
895
|
-
}
|
|
896
|
-
if (!instruction) {
|
|
897
|
-
const strongText = frame.locator('strong').first();
|
|
898
|
-
if (await strongText.count() > 0) {
|
|
899
|
-
instruction = (await strongText.textContent()) || '';
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
catch { }
|
|
904
|
-
if (instruction) {
|
|
905
|
-
results.push(`Instruction: "${instruction}"`);
|
|
906
|
-
}
|
|
907
|
-
else {
|
|
908
|
-
results.push('Instruction: (could not extract — check screenshot)');
|
|
909
|
-
}
|
|
910
|
-
const tiles = await findGridTiles(frame, provider);
|
|
911
|
-
const gridSize = tiles.length <= 9 ? '3x3' : tiles.length <= 16 ? '4x4' : `${tiles.length}-tile`;
|
|
912
|
-
results.push(`Grid: ${gridSize} (${tiles.length} tiles found, valid indices: 0-${tiles.length - 1})`);
|
|
913
|
-
_lastGridAnalyzeTime = Date.now();
|
|
914
|
-
// Clear stale tile screenshots from a previous challenge so the model never
|
|
915
|
-
// reads an old .aurix-tile-N.png that no longer matches the current grid.
|
|
916
|
-
try {
|
|
917
|
-
const home = homedir();
|
|
918
|
-
for (const f of readdirSync(home)) {
|
|
919
|
-
if (/^\.aurix-tile-(\d+|after-\d+)\.png$/.test(f)) {
|
|
920
|
-
try {
|
|
921
|
-
unlinkSync(join(home, f));
|
|
922
|
-
}
|
|
923
|
-
catch { }
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
catch { }
|
|
928
|
-
const screenshotPath = join(homedir(), '.aurix-captcha-grid.png');
|
|
929
|
-
try {
|
|
930
|
-
const gridEl = frame.locator('.rc-imageselect-table-33, .rc-imageselect-table-44, .task, .challenge-view, .geetest_panel, table').first();
|
|
931
|
-
if (await gridEl.count() > 0) {
|
|
932
|
-
await gridEl.screenshot({ path: screenshotPath });
|
|
933
|
-
}
|
|
934
|
-
else {
|
|
935
|
-
await frame.locator('body').screenshot({ path: screenshotPath });
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
catch {
|
|
939
|
-
try {
|
|
940
|
-
await page.screenshot({ path: screenshotPath });
|
|
941
|
-
}
|
|
942
|
-
catch { }
|
|
943
|
-
}
|
|
944
|
-
results.push(`Grid screenshot: ${screenshotPath}`);
|
|
945
|
-
for (let i = 0; i < tiles.length; i++) {
|
|
946
|
-
const tilePath = join(homedir(), `.aurix-tile-${i}.png`);
|
|
947
|
-
try {
|
|
948
|
-
await tiles[i].screenshot({ path: tilePath });
|
|
949
|
-
results.push(` Tile ${i}: ${tilePath}`);
|
|
950
|
-
}
|
|
951
|
-
catch {
|
|
952
|
-
results.push(` Tile ${i}: (screenshot failed)`);
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
const isRecaptcha = provider === 'recaptcha';
|
|
956
|
-
const selectedClass = isRecaptcha ? '.rc-imageselect-dynamic-selected' : '.task-image.selected, .task .selected';
|
|
957
|
-
const selectedCount = await frame.locator(selectedClass).count();
|
|
958
|
-
if (selectedCount > 0) {
|
|
959
|
-
results.push(`Already selected: ${selectedCount} tile(s)`);
|
|
960
|
-
}
|
|
961
|
-
results.push('');
|
|
962
|
-
results.push('=== IMAGE SELECTION STEPS ===');
|
|
963
|
-
results.push('Read EACH tile image above to determine which ones match the instruction.');
|
|
964
|
-
results.push('Then execute these actions IN ORDER:');
|
|
965
|
-
results.push('');
|
|
966
|
-
results.push('Step 1: For each matching tile, call: browser action="click-tile" value="<index>"');
|
|
967
|
-
results.push(' Example: if tiles 0, 3, and 5 match → click-tile 0, then click-tile 3, then click-tile 5');
|
|
968
|
-
if (provider === 'recaptcha') {
|
|
969
|
-
results.push(' IMPORTANT: After clicking a tile, a NEW tile replaces it. Read the new tile screenshot to check if it also matches.');
|
|
970
|
-
}
|
|
971
|
-
results.push('Step 2: After clicking ALL matching tiles, call: browser action="captcha-verify"');
|
|
972
|
-
results.push('Step 3: If the grid refreshes with new tiles, call captcha-grid again and repeat from Step 1');
|
|
973
|
-
results.push('');
|
|
974
|
-
results.push('Do NOT skip any step. Start by reading the tile images now.');
|
|
975
|
-
return results.join('\n');
|
|
976
|
-
}
|
|
977
383
|
export const browserTool = {
|
|
978
384
|
name: 'browser',
|
|
979
385
|
description: `Persistent Chromium browser. Profile: ~/.aurix-browser-profile.
|
|
@@ -1538,7 +944,7 @@ Sessions: session="a"/"b"/"c" for parallel browsers. proxy="host:port:user:pass"
|
|
|
1538
944
|
case 'solve-captcha': {
|
|
1539
945
|
const p = await ensureBrowser();
|
|
1540
946
|
const results = [];
|
|
1541
|
-
const _solveTimeout =
|
|
947
|
+
const _solveTimeout = 120_000;
|
|
1542
948
|
const _solveLogic = async () => {
|
|
1543
949
|
const frames = p.frames();
|
|
1544
950
|
let captchaType = 'unknown';
|
|
@@ -1590,14 +996,14 @@ Sessions: session="a"/"b"/"c" for parallel browsers. proxy="host:port:user:pass"
|
|
|
1590
996
|
try {
|
|
1591
997
|
if (recaptchaBframe) {
|
|
1592
998
|
results.push('Image challenge already visible. Auto-solving...');
|
|
1593
|
-
const maxRetries =
|
|
999
|
+
const maxRetries = 5;
|
|
1594
1000
|
let solved = false;
|
|
1595
1001
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
1596
1002
|
if (attempt > 0)
|
|
1597
1003
|
results.push(`\nRetry attempt ${attempt}/${maxRetries - 1}...`);
|
|
1598
1004
|
const solveResult = await solveCaptchaGrid(p, recaptchaBframe, 'recaptcha');
|
|
1599
1005
|
results.push(solveResult);
|
|
1600
|
-
if (solveResult.includes('
|
|
1006
|
+
if (solveResult.includes('CAPTCHA SOLVED')) {
|
|
1601
1007
|
solved = true;
|
|
1602
1008
|
break;
|
|
1603
1009
|
}
|
|
@@ -1611,6 +1017,7 @@ Sessions: session="a"/"b"/"c" for parallel browsers. proxy="host:port:user:pass"
|
|
|
1611
1017
|
solved = true;
|
|
1612
1018
|
break;
|
|
1613
1019
|
}
|
|
1020
|
+
recaptchaBframe = newChallenge;
|
|
1614
1021
|
}
|
|
1615
1022
|
if (!solved && !results.some(r => r.includes('Falling back'))) {
|
|
1616
1023
|
results.push(`\nAuto-solve exhausted after ${maxRetries} attempts. Use "captcha-grid" and "click-tile" for manual solving.`);
|
|
@@ -1634,17 +1041,17 @@ Sessions: session="a"/"b"/"c" for parallel browsers. proxy="host:port:user:pass"
|
|
|
1634
1041
|
await humanClick(checkbox, p);
|
|
1635
1042
|
await p.waitForTimeout(3000);
|
|
1636
1043
|
const updatedFrames = p.frames();
|
|
1637
|
-
|
|
1044
|
+
let challengeFrame = updatedFrames.find(f => f.url().includes('/recaptcha/') && f.url().includes('/bframe'));
|
|
1638
1045
|
if (challengeFrame) {
|
|
1639
1046
|
results.push('Image challenge appeared. Auto-solving...');
|
|
1640
|
-
const maxRetries =
|
|
1047
|
+
const maxRetries = 5;
|
|
1641
1048
|
let solved = false;
|
|
1642
1049
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
1643
1050
|
if (attempt > 0)
|
|
1644
1051
|
results.push(`\nRetry attempt ${attempt}/${maxRetries - 1}...`);
|
|
1645
1052
|
const solveResult = await solveCaptchaGrid(p, challengeFrame, 'recaptcha');
|
|
1646
1053
|
results.push(solveResult);
|
|
1647
|
-
if (solveResult.includes('
|
|
1054
|
+
if (solveResult.includes('CAPTCHA SOLVED')) {
|
|
1648
1055
|
solved = true;
|
|
1649
1056
|
break;
|
|
1650
1057
|
}
|
|
@@ -1659,6 +1066,7 @@ Sessions: session="a"/"b"/"c" for parallel browsers. proxy="host:port:user:pass"
|
|
|
1659
1066
|
solved = true;
|
|
1660
1067
|
break;
|
|
1661
1068
|
}
|
|
1069
|
+
challengeFrame = newChallenge;
|
|
1662
1070
|
}
|
|
1663
1071
|
if (!solved && !results.some(r => r.includes('Falling back'))) {
|
|
1664
1072
|
results.push(`\nAuto-solve exhausted after ${maxRetries} attempts. Use "captcha-grid" and "click-tile" for manual solving.`);
|
|
@@ -1689,14 +1097,14 @@ Sessions: session="a"/"b"/"c" for parallel browsers. proxy="host:port:user:pass"
|
|
|
1689
1097
|
}
|
|
1690
1098
|
if (challengeFrame) {
|
|
1691
1099
|
results.push('Image challenge appeared after clicking anchor. Auto-solving...');
|
|
1692
|
-
const maxRetries =
|
|
1100
|
+
const maxRetries = 5;
|
|
1693
1101
|
let solved = false;
|
|
1694
1102
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
1695
1103
|
if (attempt > 0)
|
|
1696
1104
|
results.push(`\nRetry attempt ${attempt}/${maxRetries - 1}...`);
|
|
1697
1105
|
const solveResult = await solveCaptchaGrid(p, challengeFrame, 'recaptcha');
|
|
1698
1106
|
results.push(solveResult);
|
|
1699
|
-
if (solveResult.includes('
|
|
1107
|
+
if (solveResult.includes('CAPTCHA SOLVED')) {
|
|
1700
1108
|
solved = true;
|
|
1701
1109
|
break;
|
|
1702
1110
|
}
|
|
@@ -1710,6 +1118,7 @@ Sessions: session="a"/"b"/"c" for parallel browsers. proxy="host:port:user:pass"
|
|
|
1710
1118
|
solved = true;
|
|
1711
1119
|
break;
|
|
1712
1120
|
}
|
|
1121
|
+
challengeFrame = newChallenge;
|
|
1713
1122
|
}
|
|
1714
1123
|
if (!solved && !results.some(r => r.includes('Falling back'))) {
|
|
1715
1124
|
results.push(`\nAuto-solve exhausted after ${maxRetries} attempts. Use "captcha-grid" and "click-tile" for manual solving.`);
|
|
@@ -1749,17 +1158,17 @@ Sessions: session="a"/"b"/"c" for parallel browsers. proxy="host:port:user:pass"
|
|
|
1749
1158
|
await humanClick(checkbox, p);
|
|
1750
1159
|
await p.waitForTimeout(3000);
|
|
1751
1160
|
const updatedFrames = p.frames();
|
|
1752
|
-
|
|
1161
|
+
let challengeFrame = updatedFrames.find((f) => f.url().includes('hcaptcha') && f.url().includes('challenge'));
|
|
1753
1162
|
if (challengeFrame) {
|
|
1754
1163
|
results.push('Image challenge appeared. Auto-solving...');
|
|
1755
|
-
const maxRetries =
|
|
1164
|
+
const maxRetries = 5;
|
|
1756
1165
|
let solved = false;
|
|
1757
1166
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
1758
1167
|
if (attempt > 0)
|
|
1759
1168
|
results.push(`\nRetry attempt ${attempt}/${maxRetries - 1}...`);
|
|
1760
1169
|
const solveResult = await solveCaptchaGrid(p, challengeFrame, 'hcaptcha');
|
|
1761
1170
|
results.push(solveResult);
|
|
1762
|
-
if (solveResult.includes('
|
|
1171
|
+
if (solveResult.includes('CAPTCHA SOLVED')) {
|
|
1763
1172
|
solved = true;
|
|
1764
1173
|
break;
|
|
1765
1174
|
}
|
|
@@ -1774,6 +1183,7 @@ Sessions: session="a"/"b"/"c" for parallel browsers. proxy="host:port:user:pass"
|
|
|
1774
1183
|
solved = true;
|
|
1775
1184
|
break;
|
|
1776
1185
|
}
|
|
1186
|
+
challengeFrame = newChallenge;
|
|
1777
1187
|
}
|
|
1778
1188
|
if (!solved && !results.some(r => r.includes('Falling back'))) {
|
|
1779
1189
|
results.push(`\nAuto-solve exhausted after ${maxRetries} attempts. Use "captcha-grid" and "click-tile" for manual solving.`);
|
|
@@ -2168,7 +1578,7 @@ Sessions: session="a"/"b"/"c" for parallel browsers. proxy="host:port:user:pass"
|
|
|
2168
1578
|
try {
|
|
2169
1579
|
return await Promise.race([
|
|
2170
1580
|
_solveLogic(),
|
|
2171
|
-
new Promise((_, rej) => setTimeout(() => rej(new Error('solve-captcha timed out (
|
|
1581
|
+
new Promise((_, rej) => setTimeout(() => rej(new Error('solve-captcha timed out (120s)')), _solveTimeout)),
|
|
2172
1582
|
]);
|
|
2173
1583
|
}
|
|
2174
1584
|
catch (e) {
|
|
@@ -2280,7 +1690,16 @@ Sessions: session="a"/"b"/"c" for parallel browsers. proxy="host:port:user:pass"
|
|
|
2280
1690
|
}
|
|
2281
1691
|
const tile = initialTiles[tileIndex];
|
|
2282
1692
|
const selectedBefore = await challengeFrame.locator(selectedClass).count().catch(() => 0);
|
|
2283
|
-
|
|
1693
|
+
try {
|
|
1694
|
+
await challengeFrame.evaluate((idx) => {
|
|
1695
|
+
const tds = document.querySelectorAll('table td');
|
|
1696
|
+
if (tds[idx])
|
|
1697
|
+
tds[idx].click();
|
|
1698
|
+
}, tileIndex);
|
|
1699
|
+
}
|
|
1700
|
+
catch {
|
|
1701
|
+
await tile.click({ force: true, timeout: 3000 });
|
|
1702
|
+
}
|
|
2284
1703
|
await p.waitForTimeout(300 + Math.random() * 300);
|
|
2285
1704
|
const selectedCount = await challengeFrame.locator(selectedClass).count().catch(() => 0);
|
|
2286
1705
|
const clickStatus = selectedCount !== selectedBefore
|
|
@@ -2351,16 +1770,26 @@ Sessions: session="a"/"b"/"c" for parallel browsers. proxy="host:port:user:pass"
|
|
|
2351
1770
|
if (await verifyBtn.count() === 0) {
|
|
2352
1771
|
return err('No verify button found', 'Use "captcha-grid" to analyze the challenge first');
|
|
2353
1772
|
}
|
|
2354
|
-
|
|
1773
|
+
try {
|
|
1774
|
+
await challengeFrame.evaluate(() => {
|
|
1775
|
+
const btn = document.querySelector('#recaptcha-verify-button, .rc-button-submit, .button-submit, [id*="verify"]');
|
|
1776
|
+
if (btn)
|
|
1777
|
+
btn.click();
|
|
1778
|
+
});
|
|
1779
|
+
}
|
|
1780
|
+
catch {
|
|
1781
|
+
await humanClick(verifyBtn, p);
|
|
1782
|
+
}
|
|
2355
1783
|
await p.waitForTimeout(3000);
|
|
2356
1784
|
const screenshotPath = join(homedir(), '.aurix-captcha-verify-result.png');
|
|
2357
|
-
const
|
|
2358
|
-
|
|
1785
|
+
const errorEl2 = challengeFrame.locator('.rc-imageselect-incorrect-response, .error-message, .incorrect').first();
|
|
1786
|
+
const errorVisible2 = await errorEl2.count() > 0 && await errorEl2.isVisible().catch(() => false);
|
|
1787
|
+
if (errorVisible2) {
|
|
2359
1788
|
const errorMsg = await challengeFrame.locator('.rc-imageselect-incorrect-response, .error-message').first().textContent().catch(() => 'Incorrect answer');
|
|
2360
1789
|
await p.screenshot({ path: screenshotPath });
|
|
2361
1790
|
const results = [];
|
|
2362
1791
|
results.push(`Verification failed: "${errorMsg}". Auto-retrying...`);
|
|
2363
|
-
const maxRetries =
|
|
1792
|
+
const maxRetries = 3;
|
|
2364
1793
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
2365
1794
|
results.push(`\nRetry ${attempt + 1}/${maxRetries}...`);
|
|
2366
1795
|
await p.waitForTimeout(2000);
|
|
@@ -2378,7 +1807,7 @@ Sessions: session="a"/"b"/"c" for parallel browsers. proxy="host:port:user:pass"
|
|
|
2378
1807
|
const retryProvider = retryFrame.url().includes('hcaptcha') ? 'hcaptcha' : 'recaptcha';
|
|
2379
1808
|
const solveResult = await solveCaptchaGrid(p, retryFrame, retryProvider);
|
|
2380
1809
|
results.push(solveResult);
|
|
2381
|
-
if (solveResult.includes('
|
|
1810
|
+
if (solveResult.includes('CAPTCHA SOLVED')) {
|
|
2382
1811
|
return results.join('\n');
|
|
2383
1812
|
}
|
|
2384
1813
|
}
|
|
@@ -2391,7 +1820,7 @@ Sessions: session="a"/"b"/"c" for parallel browsers. proxy="host:port:user:pass"
|
|
|
2391
1820
|
await p.screenshot({ path: screenshotPath });
|
|
2392
1821
|
const results = [];
|
|
2393
1822
|
results.push(`New challenge appeared: "${instruction}". Auto-solving...`);
|
|
2394
|
-
const maxRetries =
|
|
1823
|
+
const maxRetries = 3;
|
|
2395
1824
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
2396
1825
|
if (attempt > 0)
|
|
2397
1826
|
results.push(`\nRetry ${attempt}/${maxRetries - 1}...`);
|
|
@@ -2408,7 +1837,7 @@ Sessions: session="a"/"b"/"c" for parallel browsers. proxy="host:port:user:pass"
|
|
|
2408
1837
|
const retryProvider = retryFrame.url().includes('hcaptcha') ? 'hcaptcha' : 'recaptcha';
|
|
2409
1838
|
const solveResult = await solveCaptchaGrid(p, retryFrame, retryProvider);
|
|
2410
1839
|
results.push(solveResult);
|
|
2411
|
-
if (solveResult.includes('
|
|
1840
|
+
if (solveResult.includes('CAPTCHA SOLVED'))
|
|
2412
1841
|
return results.join('\n');
|
|
2413
1842
|
await p.waitForTimeout(2000);
|
|
2414
1843
|
}
|