Merge pull request #155 from transitive-bullshit/feature/api-redesign

pull/158/head
Travis Fischer 2022-12-17 04:01:40 -06:00 zatwierdzone przez GitHub
commit 88efa64771
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
58 zmienionych plików z 3438 dodań i 520 usunięć

Wyświetl plik

@ -4,3 +4,4 @@ dist/
node_modules/
.next/
.vercel/
third-party/

Wyświetl plik

@ -16,40 +16,63 @@ async function main() {
const email = process.env.OPENAI_EMAIL
const password = process.env.OPENAI_PASSWORD
const api = new ChatGPTAPIBrowser({ email, password, debug: true })
await api.init()
const api = new ChatGPTAPIBrowser({
email,
password,
debug: false,
minimize: true
})
await api.initSession()
const prompt = 'What is OpenAI?'
const prompt = 'Write a poem about cats.'
const response = await oraPromise(api.sendMessage(prompt), {
let res = await oraPromise(api.sendMessage(prompt), {
text: prompt
})
console.log(response)
console.log('\n' + res.response + '\n')
const prompt2 = 'Did they made OpenGPT?'
const prompt2 = 'Can you make it cuter and shorter?'
console.log(
await oraPromise(api.sendMessage(prompt2), {
res = await oraPromise(
api.sendMessage(prompt2, {
conversationId: res.conversationId,
parentMessageId: res.messageId
}),
{
text: prompt2
})
}
)
console.log('\n' + res.response + '\n')
const prompt3 = 'Who founded this institute?'
const prompt3 = 'Now write it in French.'
console.log(
await oraPromise(api.sendMessage(prompt3), {
res = await oraPromise(
api.sendMessage(prompt3, {
conversationId: res.conversationId,
parentMessageId: res.messageId
}),
{
text: prompt3
})
}
)
console.log('\n' + res.response + '\n')
const prompt4 = 'Who is that?'
const prompt4 = 'What were we talking about again?'
console.log(
await oraPromise(api.sendMessage(prompt4), {
res = await oraPromise(
api.sendMessage(prompt4, {
conversationId: res.conversationId,
parentMessageId: res.messageId
}),
{
text: prompt4
})
}
)
console.log('\n' + res.response + '\n')
// close the browser at the end
await api.closeSession()
}
main().catch((err) => {

Wyświetl plik

@ -22,41 +22,56 @@ async function main() {
})
const api = new ChatGPTAPI({ ...authInfo })
await api.ensureAuth()
await api.initSession()
const conversation = api.getConversation()
const prompt = 'Write a poem about cats.'
const prompt = 'What is OpenAI?'
const response = await oraPromise(conversation.sendMessage(prompt), {
let res = await oraPromise(api.sendMessage(prompt), {
text: prompt
})
console.log(response)
console.log('\n' + res.response + '\n')
const prompt2 = 'Did they made OpenGPT?'
const prompt2 = 'Can you make it cuter and shorter?'
console.log(
await oraPromise(conversation.sendMessage(prompt2), {
res = await oraPromise(
api.sendMessage(prompt2, {
conversationId: res.conversationId,
parentMessageId: res.messageId
}),
{
text: prompt2
})
}
)
console.log('\n' + res.response + '\n')
const prompt3 = 'Who founded this institute?'
const prompt3 = 'Now write it in French.'
console.log(
await oraPromise(conversation.sendMessage(prompt3), {
res = await oraPromise(
api.sendMessage(prompt3, {
conversationId: res.conversationId,
parentMessageId: res.messageId
}),
{
text: prompt3
})
}
)
console.log('\n' + res.response + '\n')
const prompt4 = 'Who is that?'
const prompt4 = 'What were we talking about again?'
console.log(
await oraPromise(conversation.sendMessage(prompt4), {
res = await oraPromise(
api.sendMessage(prompt4, {
conversationId: res.conversationId,
parentMessageId: res.messageId
}),
{
text: prompt4
})
}
)
console.log('\n' + res.response + '\n')
await api.closeSession()
}
main().catch((err) => {

Wyświetl plik

@ -1,4 +1,3 @@
import delay from 'delay'
import dotenv from 'dotenv-safe'
import { oraPromise } from 'ora'
@ -23,24 +22,21 @@ async function main() {
debug: false,
minimize: true
})
await api.init()
await api.initSession()
const prompt =
'Write a python version of bubble sort. Do not include example usage.'
const response = await oraPromise(api.sendMessage(prompt), {
const res = await oraPromise(api.sendMessage(prompt), {
text: prompt
})
console.log(res.response)
await api.close()
return response
// close the browser at the end
await api.closeSession()
}
main()
.then((res) => {
console.log(res)
})
.catch((err) => {
console.error(err)
process.exit(1)
})
main().catch((err) => {
console.error(err)
process.exit(1)
})

Wyświetl plik

@ -0,0 +1,167 @@
[chatgpt](../readme.md) / [Exports](../modules.md) / AChatGPTAPI
# Class: AChatGPTAPI
## Hierarchy
- **`AChatGPTAPI`**
↳ [`ChatGPTAPI`](ChatGPTAPI.md)
↳ [`ChatGPTAPIBrowser`](ChatGPTAPIBrowser.md)
## Table of contents
### Constructors
- [constructor](AChatGPTAPI.md#constructor)
### Methods
- [closeSession](AChatGPTAPI.md#closesession)
- [getIsAuthenticated](AChatGPTAPI.md#getisauthenticated)
- [initSession](AChatGPTAPI.md#initsession)
- [refreshSession](AChatGPTAPI.md#refreshsession)
- [resetSession](AChatGPTAPI.md#resetsession)
- [sendMessage](AChatGPTAPI.md#sendmessage)
## Constructors
### constructor
**new AChatGPTAPI**()
## Methods
### closeSession
`Abstract` **closeSession**(): `Promise`<`void`\>
Closes the active session.
**`Throws`**
An error if it fails.
#### Returns
`Promise`<`void`\>
#### Defined in
[src/abstract-chatgpt-api.ts:69](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/abstract-chatgpt-api.ts#L69)
___
### getIsAuthenticated
`Abstract` **getIsAuthenticated**(): `Promise`<`boolean`\>
#### Returns
`Promise`<`boolean`\>
`true` if the client is authenticated with a valid session or `false`
otherwise.
#### Defined in
[src/abstract-chatgpt-api.ts:39](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/abstract-chatgpt-api.ts#L39)
___
### initSession
`Abstract` **initSession**(): `Promise`<`void`\>
Performs any async initialization work required to ensure that this API is
properly authenticated.
**`Throws`**
An error if the session failed to initialize properly.
#### Returns
`Promise`<`void`\>
#### Defined in
[src/abstract-chatgpt-api.ts:10](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/abstract-chatgpt-api.ts#L10)
___
### refreshSession
`Abstract` **refreshSession**(): `Promise`<`any`\>
Refreshes the current ChatGPT session.
Useful for bypassing 403 errors when Cloudflare clearance tokens expire.
**`Throws`**
An error if it fails.
#### Returns
`Promise`<`any`\>
Access credentials for the new session.
#### Defined in
[src/abstract-chatgpt-api.ts:49](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/abstract-chatgpt-api.ts#L49)
___
### resetSession
**resetSession**(): `Promise`<`any`\>
Closes the current ChatGPT session and starts a new one.
Useful for bypassing 401 errors when sessions expire.
**`Throws`**
An error if it fails.
#### Returns
`Promise`<`any`\>
Access credentials for the new session.
#### Defined in
[src/abstract-chatgpt-api.ts:59](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/abstract-chatgpt-api.ts#L59)
___
### sendMessage
`Abstract` **sendMessage**(`message`, `opts?`): `Promise`<[`ChatResponse`](../modules.md#chatresponse)\>
Sends a message to ChatGPT, waits for the response to resolve, and returns
the response.
If you want to receive a stream of partial responses, use `opts.onProgress`.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `message` | `string` | The prompt message to send |
| `opts?` | [`SendMessageOptions`](../modules.md#sendmessageoptions) | - |
#### Returns
`Promise`<[`ChatResponse`](../modules.md#chatresponse)\>
The response from ChatGPT, including `conversationId`, `messageId`, and
the `response` text.
#### Defined in
[src/abstract-chatgpt-api.ts:30](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/abstract-chatgpt-api.ts#L30)

Wyświetl plik

@ -2,6 +2,12 @@
# Class: ChatGPTAPI
## Hierarchy
- [`AChatGPTAPI`](AChatGPTAPI.md)
**`ChatGPTAPI`**
## Table of contents
### Constructors
@ -17,10 +23,11 @@
### Methods
- [ensureAuth](ChatGPTAPI.md#ensureauth)
- [getConversation](ChatGPTAPI.md#getconversation)
- [closeSession](ChatGPTAPI.md#closesession)
- [getIsAuthenticated](ChatGPTAPI.md#getisauthenticated)
- [refreshAccessToken](ChatGPTAPI.md#refreshaccesstoken)
- [initSession](ChatGPTAPI.md#initsession)
- [refreshSession](ChatGPTAPI.md#refreshsession)
- [resetSession](ChatGPTAPI.md#resetsession)
- [sendMessage](ChatGPTAPI.md#sendmessage)
- [sendModeration](ChatGPTAPI.md#sendmoderation)
@ -51,9 +58,13 @@ to obtain your `clearanceToken`.
| `opts.sessionToken` | `string` | = **Required** OpenAI session token which can be found in a valid session's cookies (see readme for instructions) |
| `opts.userAgent?` | `string` | **`Default Value`** `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36'` * |
#### Overrides
[AChatGPTAPI](AChatGPTAPI.md).[constructor](AChatGPTAPI.md#constructor)
#### Defined in
[src/chatgpt-api.ts:45](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api.ts#L45)
[src/chatgpt-api.ts:45](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api.ts#L45)
## Accessors
@ -69,7 +80,7 @@ Gets the current Cloudflare clearance token (`cf_clearance` cookie value).
#### Defined in
[src/chatgpt-api.ts:137](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api.ts#L137)
[src/chatgpt-api.ts:143](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api.ts#L143)
___
@ -85,7 +96,7 @@ Gets the current session token.
#### Defined in
[src/chatgpt-api.ts:132](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api.ts#L132)
[src/chatgpt-api.ts:138](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api.ts#L138)
___
@ -101,7 +112,7 @@ Gets the currently signed-in user, if authenticated, `null` otherwise.
#### Defined in
[src/chatgpt-api.ts:127](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api.ts#L127)
[src/chatgpt-api.ts:133](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api.ts#L133)
___
@ -117,51 +128,31 @@ Gets the current user agent.
#### Defined in
[src/chatgpt-api.ts:142](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api.ts#L142)
[src/chatgpt-api.ts:148](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api.ts#L148)
## Methods
### ensureAuth
### closeSession
**ensureAuth**(): `Promise`<`string`\>
**closeSession**(): `Promise`<`void`\>
Refreshes the client's access token which will succeed only if the session
is still valid.
Closes the active session.
**`Throws`**
An error if it fails.
#### Returns
`Promise`<`string`\>
`Promise`<`void`\>
#### Overrides
[AChatGPTAPI](AChatGPTAPI.md).[closeSession](AChatGPTAPI.md#closesession)
#### Defined in
[src/chatgpt-api.ts:359](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api.ts#L359)
___
### getConversation
**getConversation**(`opts?`): [`ChatGPTConversation`](ChatGPTConversation.md)
Gets a new ChatGPTConversation instance, which can be used to send multiple
messages as part of a single conversation.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `opts` | `Object` | - |
| `opts.conversationId?` | `string` | Optional ID of the previous message in a conversation |
| `opts.parentMessageId?` | `string` | Optional ID of the previous message in a conversation |
#### Returns
[`ChatGPTConversation`](ChatGPTConversation.md)
The new conversation instance
#### Defined in
[src/chatgpt-api.ts:465](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api.ts#L465)
[src/chatgpt-api.ts:470](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api.ts#L470)
___
@ -176,15 +167,40 @@ ___
`true` if the client has a valid acces token or `false` if refreshing
the token fails.
#### Overrides
[AChatGPTAPI](AChatGPTAPI.md).[getIsAuthenticated](AChatGPTAPI.md#getisauthenticated)
#### Defined in
[src/chatgpt-api.ts:346](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api.ts#L346)
[src/chatgpt-api.ts:367](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api.ts#L367)
___
### refreshAccessToken
### initSession
**refreshAccessToken**(): `Promise`<`string`\>
**initSession**(): `Promise`<`void`\>
Refreshes the client's access token which will succeed only if the session
is valid.
#### Returns
`Promise`<`void`\>
#### Overrides
[AChatGPTAPI](AChatGPTAPI.md).[initSession](AChatGPTAPI.md#initsession)
#### Defined in
[src/chatgpt-api.ts:156](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api.ts#L156)
___
### refreshSession
**refreshSession**(): `Promise`<`string`\>
Attempts to refresh the current access token using the ChatGPT
`sessionToken` cookie.
@ -202,15 +218,47 @@ An error if refreshing the access token fails.
A valid access token
#### Overrides
[AChatGPTAPI](AChatGPTAPI.md).[refreshSession](AChatGPTAPI.md#refreshsession)
#### Defined in
[src/chatgpt-api.ts:373](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api.ts#L373)
[src/chatgpt-api.ts:386](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api.ts#L386)
___
### resetSession
**resetSession**(): `Promise`<`any`\>
Closes the current ChatGPT session and starts a new one.
Useful for bypassing 401 errors when sessions expire.
**`Throws`**
An error if it fails.
#### Returns
`Promise`<`any`\>
Access credentials for the new session.
#### Inherited from
[AChatGPTAPI](AChatGPTAPI.md).[resetSession](AChatGPTAPI.md#resetsession)
#### Defined in
[src/abstract-chatgpt-api.ts:59](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/abstract-chatgpt-api.ts#L59)
___
### sendMessage
**sendMessage**(`message`, `opts?`): `Promise`<`string`\>
**sendMessage**(`message`, `opts?`): `Promise`<[`ChatResponse`](../modules.md#chatresponse)\>
Sends a message to ChatGPT, waits for the response to resolve, and returns
the response.
@ -229,13 +277,17 @@ helper.
#### Returns
`Promise`<`string`\>
`Promise`<[`ChatResponse`](../modules.md#chatresponse)\>
The response from ChatGPT
#### Overrides
[AChatGPTAPI](AChatGPTAPI.md).[sendMessage](AChatGPTAPI.md#sendmessage)
#### Defined in
[src/chatgpt-api.ts:167](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api.ts#L167)
[src/chatgpt-api.ts:180](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api.ts#L180)
___
@ -255,4 +307,4 @@ ___
#### Defined in
[src/chatgpt-api.ts:303](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api.ts#L303)
[src/chatgpt-api.ts:324](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api.ts#L324)

Wyświetl plik

@ -2,20 +2,31 @@
# Class: ChatGPTAPIBrowser
## Hierarchy
- [`AChatGPTAPI`](AChatGPTAPI.md)
**`ChatGPTAPIBrowser`**
## Table of contents
### Constructors
- [constructor](ChatGPTAPIBrowser.md#constructor)
### Accessors
- [isChatPage](ChatGPTAPIBrowser.md#ischatpage)
### Methods
- [\_onRequest](ChatGPTAPIBrowser.md#_onrequest)
- [\_onResponse](ChatGPTAPIBrowser.md#_onresponse)
- [close](ChatGPTAPIBrowser.md#close)
- [closeSession](ChatGPTAPIBrowser.md#closesession)
- [getIsAuthenticated](ChatGPTAPIBrowser.md#getisauthenticated)
- [handle403Error](ChatGPTAPIBrowser.md#handle403error)
- [init](ChatGPTAPIBrowser.md#init)
- [initSession](ChatGPTAPIBrowser.md#initsession)
- [refreshSession](ChatGPTAPIBrowser.md#refreshsession)
- [resetSession](ChatGPTAPIBrowser.md#resetsession)
- [resetThread](ChatGPTAPIBrowser.md#resetthread)
- [sendMessage](ChatGPTAPIBrowser.md#sendmessage)
@ -25,25 +36,43 @@
**new ChatGPTAPIBrowser**(`opts`)
Creates a new client wrapper for automating the ChatGPT webapp.
Creates a new client for automating the ChatGPT webapp.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `opts` | `Object` | - |
| `opts.browserPath?` | `string` | **`Default Value`** `undefined` * |
| `opts.captchaToken?` | `string` | **`Default Value`** `undefined` * |
| `opts.debug?` | `boolean` | **`Default Value`** `false` * |
| `opts.email` | `string` | - |
| `opts.executablePath?` | `string` | **`Default Value`** `undefined` * |
| `opts.isGoogleLogin?` | `boolean` | **`Default Value`** `false` * |
| `opts.markdown?` | `boolean` | **`Default Value`** `true` * |
| `opts.minimize?` | `boolean` | **`Default Value`** `true` * |
| `opts.password` | `string` | - |
#### Overrides
[AChatGPTAPI](AChatGPTAPI.md).[constructor](AChatGPTAPI.md#constructor)
#### Defined in
[src/chatgpt-api-browser.ts:32](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api-browser.ts#L32)
[src/chatgpt-api-browser.ts:36](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api-browser.ts#L36)
## Accessors
### isChatPage
`get` **isChatPage**(): `boolean`
#### Returns
`boolean`
#### Defined in
[src/chatgpt-api-browser.ts:524](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api-browser.ts#L524)
## Methods
@ -63,7 +92,7 @@ Creates a new client wrapper for automating the ChatGPT webapp.
#### Defined in
[src/chatgpt-api-browser.ts:153](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api-browser.ts#L153)
[src/chatgpt-api-browser.ts:173](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api-browser.ts#L173)
___
@ -83,21 +112,31 @@ ___
#### Defined in
[src/chatgpt-api-browser.ts:190](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api-browser.ts#L190)
[src/chatgpt-api-browser.ts:210](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api-browser.ts#L210)
___
### close
### closeSession
**close**(): `Promise`<`void`\>
**closeSession**(): `Promise`<`void`\>
Closes the active session.
**`Throws`**
An error if it fails.
#### Returns
`Promise`<`void`\>
#### Overrides
[AChatGPTAPI](AChatGPTAPI.md).[closeSession](AChatGPTAPI.md#closesession)
#### Defined in
[src/chatgpt-api-browser.ts:453](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api-browser.ts#L453)
[src/chatgpt-api-browser.ts:512](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api-browser.ts#L512)
___
@ -109,37 +148,81 @@ ___
`Promise`<`boolean`\>
`true` if the client is authenticated with a valid session or `false`
otherwise.
#### Overrides
[AChatGPTAPI](AChatGPTAPI.md).[getIsAuthenticated](AChatGPTAPI.md#getisauthenticated)
#### Defined in
[src/chatgpt-api-browser.ts:257](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api-browser.ts#L257)
[src/chatgpt-api-browser.ts:302](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api-browser.ts#L302)
___
### handle403Error
### initSession
**handle403Error**(): `Promise`<`void`\>
**initSession**(): `Promise`<`void`\>
Performs any async initialization work required to ensure that this API is
properly authenticated.
**`Throws`**
An error if the session failed to initialize properly.
#### Returns
`Promise`<`void`\>
#### Overrides
[AChatGPTAPI](AChatGPTAPI.md).[initSession](AChatGPTAPI.md#initsession)
#### Defined in
[src/chatgpt-api-browser.ts:238](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api-browser.ts#L238)
[src/chatgpt-api-browser.ts:94](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api-browser.ts#L94)
___
### init
### refreshSession
**init**(): `Promise`<`boolean`\>
**refreshSession**(): `Promise`<`void`\>
Attempts to handle 403 errors by refreshing the page.
#### Returns
`Promise`<`boolean`\>
`Promise`<`void`\>
#### Overrides
[AChatGPTAPI](AChatGPTAPI.md).[refreshSession](AChatGPTAPI.md#refreshsession)
#### Defined in
[src/chatgpt-api-browser.ts:76](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api-browser.ts#L76)
[src/chatgpt-api-browser.ts:282](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api-browser.ts#L282)
___
### resetSession
**resetSession**(): `Promise`<`void`\>
Attempts to handle 401 errors by re-authenticating.
#### Returns
`Promise`<`void`\>
#### Overrides
[AChatGPTAPI](AChatGPTAPI.md).[resetSession](AChatGPTAPI.md#resetsession)
#### Defined in
[src/chatgpt-api-browser.ts:263](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api-browser.ts#L263)
___
@ -153,25 +236,37 @@ ___
#### Defined in
[src/chatgpt-api-browser.ts:445](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api-browser.ts#L445)
[src/chatgpt-api-browser.ts:504](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api-browser.ts#L504)
___
### sendMessage
**sendMessage**(`message`, `opts?`): `Promise`<`string`\>
**sendMessage**(`message`, `opts?`): `Promise`<[`ChatResponse`](../modules.md#chatresponse)\>
Sends a message to ChatGPT, waits for the response to resolve, and returns
the response.
If you want to receive a stream of partial responses, use `opts.onProgress`.
#### Parameters
| Name | Type |
| :------ | :------ |
| `message` | `string` |
| `opts` | [`SendMessageOptions`](../modules.md#sendmessageoptions) |
| Name | Type | Description |
| :------ | :------ | :------ |
| `message` | `string` | The prompt message to send |
| `opts` | [`SendMessageOptions`](../modules.md#sendmessageoptions) | - |
#### Returns
`Promise`<`string`\>
`Promise`<[`ChatResponse`](../modules.md#chatresponse)\>
The response from ChatGPT, including `conversationId`, `messageId`, and
the `response` text.
#### Overrides
[AChatGPTAPI](AChatGPTAPI.md).[sendMessage](AChatGPTAPI.md#sendmessage)
#### Defined in
[src/chatgpt-api-browser.ts:330](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-api-browser.ts#L330)
[src/chatgpt-api-browser.ts:379](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/chatgpt-api-browser.ts#L379)

Wyświetl plik

@ -1,107 +0,0 @@
[chatgpt](../readme.md) / [Exports](../modules.md) / ChatGPTConversation
# Class: ChatGPTConversation
A conversation wrapper around the ChatGPTAPI. This allows you to send
multiple messages to ChatGPT and receive responses, without having to
manually pass the conversation ID and parent message ID for each message.
## Table of contents
### Constructors
- [constructor](ChatGPTConversation.md#constructor)
### Properties
- [api](ChatGPTConversation.md#api)
- [conversationId](ChatGPTConversation.md#conversationid)
- [parentMessageId](ChatGPTConversation.md#parentmessageid)
### Methods
- [sendMessage](ChatGPTConversation.md#sendmessage)
## Constructors
### constructor
**new ChatGPTConversation**(`api`, `opts?`)
Creates a new conversation wrapper around the ChatGPT API.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `api` | [`ChatGPTAPI`](ChatGPTAPI.md) | The ChatGPT API instance to use |
| `opts` | `Object` | - |
| `opts.conversationId?` | `string` | Optional ID of a conversation to continue |
| `opts.parentMessageId?` | `string` | Optional ID of the previous message in the conversation |
#### Defined in
[src/chatgpt-conversation.ts:21](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-conversation.ts#L21)
## Properties
### api
**api**: [`ChatGPTAPI`](ChatGPTAPI.md)
#### Defined in
[src/chatgpt-conversation.ts:10](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-conversation.ts#L10)
___
### conversationId
**conversationId**: `string` = `undefined`
#### Defined in
[src/chatgpt-conversation.ts:11](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-conversation.ts#L11)
___
### parentMessageId
**parentMessageId**: `string` = `undefined`
#### Defined in
[src/chatgpt-conversation.ts:12](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-conversation.ts#L12)
## Methods
### sendMessage
**sendMessage**(`message`, `opts?`): `Promise`<`string`\>
Sends a message to ChatGPT, waits for the response to resolve, and returns
the response.
If this is the first message in the conversation, the conversation ID and
parent message ID will be automatically set.
This allows you to send multiple messages to ChatGPT and receive responses,
without having to manually pass the conversation ID and parent message ID
for each message.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `message` | `string` | The prompt message to send |
| `opts` | [`SendConversationMessageOptions`](../modules.md#sendconversationmessageoptions) | - |
#### Returns
`Promise`<`string`\>
The response from ChatGPT
#### Defined in
[src/chatgpt-conversation.ts:48](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/chatgpt-conversation.ts#L48)

Wyświetl plik

@ -66,7 +66,7 @@ node_modules/.pnpm/typescript@4.9.3/node_modules/typescript/lib/lib.es2022.error
#### Defined in
[src/types.ts:298](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L298)
[src/types.ts:297](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L297)
___
@ -76,7 +76,7 @@ ___
#### Defined in
[src/types.ts:297](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L297)
[src/types.ts:296](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L296)
___
@ -86,7 +86,7 @@ ___
#### Defined in
[src/types.ts:295](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L295)
[src/types.ts:294](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L294)
___
@ -96,4 +96,4 @@ ___
#### Defined in
[src/types.ts:296](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L296)
[src/types.ts:295](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L295)

Wyświetl plik

@ -6,9 +6,9 @@
### Classes
- [AChatGPTAPI](classes/AChatGPTAPI.md)
- [ChatGPTAPI](classes/ChatGPTAPI.md)
- [ChatGPTAPIBrowser](classes/ChatGPTAPIBrowser.md)
- [ChatGPTConversation](classes/ChatGPTConversation.md)
- [ChatGPTError](classes/ChatGPTError.md)
### Type Aliases
@ -59,7 +59,7 @@
#### Defined in
[src/types.ts:109](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L109)
[src/types.ts:109](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L109)
___
@ -72,17 +72,15 @@ ___
| Name | Type |
| :------ | :------ |
| `conversationId?` | `string` |
| `conversationResponse?` | [`ConversationResponseEvent`](modules.md#conversationresponseevent) |
| `error` | { `message`: `string` ; `statusCode?`: `number` ; `statusText?`: `string` } |
| `error.message` | `string` |
| `error.statusCode?` | `number` |
| `error.statusText?` | `string` |
| `messageId?` | `string` |
| `response` | ``null`` |
#### Defined in
[src/types.ts:301](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L301)
[src/types.ts:300](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L300)
___
@ -95,14 +93,12 @@ ___
| Name | Type |
| :------ | :------ |
| `conversationId` | `string` |
| `conversationResponse?` | [`ConversationResponseEvent`](modules.md#conversationresponseevent) |
| `error` | ``null`` |
| `messageId` | `string` |
| `response` | `string` |
#### Defined in
[src/types.ts:309](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L309)
[src/types.ts:306](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L306)
___
@ -112,7 +108,7 @@ ___
#### Defined in
[src/types.ts:1](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L1)
[src/types.ts:1](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L1)
___
@ -134,7 +130,7 @@ https://chat.openapi.com/backend-api/conversation
#### Defined in
[src/types.ts:134](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L134)
[src/types.ts:134](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L134)
___
@ -152,7 +148,7 @@ ___
#### Defined in
[src/types.ts:251](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L251)
[src/types.ts:251](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L251)
___
@ -177,7 +173,7 @@ ___
#### Defined in
[src/types.ts:257](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L257)
[src/types.ts:257](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L257)
___
@ -187,7 +183,7 @@ ___
#### Defined in
[src/types.ts:276](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L276)
[src/types.ts:276](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L276)
___
@ -204,7 +200,7 @@ ___
#### Defined in
[src/types.ts:270](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L270)
[src/types.ts:270](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L270)
___
@ -226,7 +222,7 @@ https://chat.openapi.com/backend-api/conversation/message_feedback
#### Defined in
[src/types.ts:193](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L193)
[src/types.ts:193](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L193)
___
@ -236,7 +232,7 @@ ___
#### Defined in
[src/types.ts:249](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L249)
[src/types.ts:249](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L249)
___
@ -256,7 +252,7 @@ ___
#### Defined in
[src/types.ts:222](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L222)
[src/types.ts:222](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L222)
___
@ -266,7 +262,7 @@ ___
#### Defined in
[src/types.ts:220](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L220)
[src/types.ts:220](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L220)
___
@ -276,7 +272,7 @@ ___
#### Defined in
[src/types.ts:275](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L275)
[src/types.ts:275](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L275)
___
@ -294,7 +290,7 @@ ___
#### Defined in
[src/types.ts:77](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L77)
[src/types.ts:77](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L77)
___
@ -312,7 +308,7 @@ https://chat.openapi.com/backend-api/models
#### Defined in
[src/types.ts:70](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L70)
[src/types.ts:70](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L70)
___
@ -331,7 +327,7 @@ https://chat.openapi.com/backend-api/moderations
#### Defined in
[src/types.ts:97](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L97)
[src/types.ts:97](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L97)
___
@ -351,7 +347,7 @@ https://chat.openapi.com/backend-api/moderations
#### Defined in
[src/types.ts:114](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L114)
[src/types.ts:114](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L114)
___
@ -373,7 +369,7 @@ to authenticate with the unofficial ChatGPT API.
#### Defined in
[src/openai-auth.ts:20](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/openai-auth.ts#L20)
[src/openai-auth.ts:27](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/openai-auth.ts#L27)
___
@ -391,7 +387,7 @@ ___
#### Defined in
[src/types.ts:161](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L161)
[src/types.ts:161](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L161)
___
@ -408,7 +404,7 @@ ___
#### Defined in
[src/types.ts:178](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L178)
[src/types.ts:178](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L178)
___
@ -418,7 +414,7 @@ ___
#### Defined in
[src/types.ts:3](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L3)
[src/types.ts:3](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L3)
___
@ -428,7 +424,7 @@ ___
#### Defined in
[src/types.ts:289](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L289)
[src/types.ts:288](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L288)
___
@ -444,14 +440,13 @@ ___
| `action?` | [`MessageActionType`](modules.md#messageactiontype) |
| `conversationId?` | `string` |
| `messageId?` | `string` |
| `onConversationResponse?` | (`response`: [`ConversationResponseEvent`](modules.md#conversationresponseevent)) => `void` |
| `onProgress?` | (`partialResponse`: `string`) => `void` |
| `onProgress?` | (`partialResponse`: [`ChatResponse`](modules.md#chatresponse)) => `void` |
| `parentMessageId?` | `string` |
| `timeoutMs?` | `number` |
#### Defined in
[src/types.ts:278](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L278)
[src/types.ts:278](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L278)
___
@ -472,7 +467,7 @@ https://chat.openapi.com/api/auth/session
#### Defined in
[src/types.ts:8](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L8)
[src/types.ts:8](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L8)
___
@ -494,7 +489,7 @@ ___
#### Defined in
[src/types.ts:30](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/types.ts#L30)
[src/types.ts:30](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/types.ts#L30)
## Functions
@ -521,7 +516,7 @@ included them in here.
#### Defined in
[src/utils.ts:73](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/utils.ts#L73)
[src/utils.ts:73](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/utils.ts#L73)
___
@ -537,7 +532,7 @@ Gets the default path to chrome's executable for the current platform.
#### Defined in
[src/openai-auth.ts:224](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/openai-auth.ts#L224)
[src/openai-auth.ts:299](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/openai-auth.ts#L299)
___
@ -553,7 +548,7 @@ recognizes it and blocks access.
| Name | Type |
| :------ | :------ |
| `opts` | `PuppeteerLaunchOptions` & { `captchaToken?`: `string` } |
| `opts` | `PuppeteerLaunchOptions` & { `captchaToken?`: `string` ; `nopechaKey?`: `string` } |
#### Returns
@ -561,7 +556,7 @@ recognizes it and blocks access.
#### Defined in
[src/openai-auth.ts:186](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/openai-auth.ts#L186)
[src/openai-auth.ts:201](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/openai-auth.ts#L201)
___
@ -603,7 +598,7 @@ with your updated credentials.
#### Defined in
[src/openai-auth.ts:42](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/openai-auth.ts#L42)
[src/openai-auth.ts:49](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/openai-auth.ts#L49)
___
@ -623,7 +618,7 @@ ___
#### Defined in
[src/utils.ts:39](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/utils.ts#L39)
[src/utils.ts:39](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/utils.ts#L39)
___
@ -643,7 +638,7 @@ ___
#### Defined in
[src/utils.ts:12](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/utils.ts#L12)
[src/utils.ts:12](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/utils.ts#L12)
___
@ -663,7 +658,7 @@ ___
#### Defined in
[src/utils.ts:29](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/utils.ts#L29)
[src/utils.ts:29](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/utils.ts#L29)
___
@ -683,4 +678,4 @@ ___
#### Defined in
[src/utils.ts:19](https://github.com/transitive-bullshit/chatgpt-api/blob/d685b78/src/utils.ts#L19)
[src/utils.ts:19](https://github.com/transitive-bullshit/chatgpt-api/blob/2937409/src/utils.ts#L19)

Wyświetl plik

@ -19,9 +19,10 @@ const api = new ChatGPTAPIBrowser({
email: process.env.OPENAI_EMAIL,
password: process.env.OPENAI_PASSWORD
})
await api.init()
await api.initSession()
const response = await api.sendMessage('Hello World!')
const result = await api.sendMessage('Hello World!')
console.log(result.response)
```
Note that this solution is not lightweight, but it does work a lot more consistently than the REST API-based versions. I'm currently using this solution to power 10 OpenAI accounts concurrently across 10 minimized Chrome windows for my [Twitter bot](https://github.com/transitive-bullshit/chatgpt-twitter-bot). 😂
@ -88,15 +89,13 @@ async function example() {
})
const api = new ChatGPTAPI({ ...openAIAuth })
await api.ensureAuth()
await api.initSession()
// send a message and wait for the response
const response = await api.sendMessage(
'Write a python version of bubble sort.'
)
const result = await api.sendMessage('Write a python version of bubble sort.')
// response is a markdown-formatted string
console.log(response)
// result.response is a markdown-formatted string
console.log(result.response)
}
```
@ -112,10 +111,10 @@ async function example() {
password: process.env.OPENAI_PASSWORD
})
await api.init()
await api.initSession()
const response = await api.sendMessage('Hello World!')
console.log(response)
const result = await api.sendMessage('Hello World!')
console.log(result.response)
}
```
@ -125,21 +124,30 @@ ChatGPT responses are formatted as markdown by default. If you want to work with
const api = new ChatGPTAPI({ ...openAIAuth, markdown: false })
```
If you want to automatically track the conversation, you can use `ChatGPTAPI.getConversation()`:
If you want to track the conversation, use the `conversationId` and `messageId` in the result object, and pass them to `sendMessage` as `conversationId` and `parentMessageId` respectively.
```ts
const api = new ChatGPTAPI({ ...openAIAuth, markdown: false })
const conversation = api.getConversation()
await api.initSession()
// send a message and wait for the response
const response0 = await conversation.sendMessage('What is OpenAI?')
let res = await conversation.sendMessage('What is OpenAI?')
console.log(res.response)
// send a follow-up
const response1 = await conversation.sendMessage('Can you expand on that?')
res = await conversation.sendMessage('Can you expand on that?', {
conversationId: res.conversationId,
parentMessageId: res.messageId
})
console.log(res.response)
// send another follow-up
const response2 = await conversation.sendMessage('Oh cool; thank you')
// send a follow-up
res = await conversation.sendMessage('What were we talking about?', {
conversationId: res.conversationId,
parentMessageId: res.messageId
})
console.log(res.response)
```
Sometimes, ChatGPT will hang for an extended period of time before beginning to respond. This may be due to rate limiting or it may be due to OpenAI's servers being overloaded.
@ -153,8 +161,6 @@ const response = await api.sendMessage('this is a timeout test', {
})
```
You can stream responses using the `onProgress` or `onConversationResponse` callbacks. See the [docs](./docs/classes/ChatGPTAPI.md) for more details.
<details>
<summary>Usage in CommonJS (Dynamic import)</summary>
@ -169,10 +175,10 @@ async function example() {
})
const api = new ChatGPTAPI({ ...openAIAuth })
await api.ensureAuth()
await api.initSession()
const response = await api.sendMessage('Hello World!')
console.log(response)
const result = await api.sendMessage('Hello World!')
console.log(result)
}
```

Wyświetl plik

@ -16,7 +16,8 @@
}
},
"files": [
"build"
"build",
"third-party"
],
"engines": {
"node": ">=18"

Wyświetl plik

@ -17,9 +17,10 @@ const api = new ChatGPTAPIBrowser({
email: process.env.OPENAI_EMAIL,
password: process.env.OPENAI_PASSWORD
})
await api.init()
await api.initSession()
const response = await api.sendMessage('Hello World!')
const result = await api.sendMessage('Hello World!')
console.log(result.response)
```
Note that this solution is not lightweight, but it does work a lot more consistently than the REST API-based versions. I'm currently using this solution to power 10 OpenAI accounts concurrently across 10 minimized Chrome windows for my [Twitter bot](https://github.com/transitive-bullshit/chatgpt-twitter-bot). 😂
@ -86,15 +87,13 @@ async function example() {
})
const api = new ChatGPTAPI({ ...openAIAuth })
await api.ensureAuth()
await api.initSession()
// send a message and wait for the response
const response = await api.sendMessage(
'Write a python version of bubble sort.'
)
const result = await api.sendMessage('Write a python version of bubble sort.')
// response is a markdown-formatted string
console.log(response)
// result.response is a markdown-formatted string
console.log(result.response)
}
```
@ -110,10 +109,10 @@ async function example() {
password: process.env.OPENAI_PASSWORD
})
await api.init()
await api.initSession()
const response = await api.sendMessage('Hello World!')
console.log(response)
const result = await api.sendMessage('Hello World!')
console.log(result.response)
}
```
@ -123,21 +122,30 @@ ChatGPT responses are formatted as markdown by default. If you want to work with
const api = new ChatGPTAPI({ ...openAIAuth, markdown: false })
```
If you want to automatically track the conversation, you can use `ChatGPTAPI.getConversation()`:
If you want to track the conversation, use the `conversationId` and `messageId` in the result object, and pass them to `sendMessage` as `conversationId` and `parentMessageId` respectively.
```ts
const api = new ChatGPTAPI({ ...openAIAuth, markdown: false })
const conversation = api.getConversation()
await api.initSession()
// send a message and wait for the response
const response0 = await conversation.sendMessage('What is OpenAI?')
let res = await conversation.sendMessage('What is OpenAI?')
console.log(res.response)
// send a follow-up
const response1 = await conversation.sendMessage('Can you expand on that?')
res = await conversation.sendMessage('Can you expand on that?', {
conversationId: res.conversationId,
parentMessageId: res.messageId
})
console.log(res.response)
// send another follow-up
const response2 = await conversation.sendMessage('Oh cool; thank you')
// send a follow-up
res = await conversation.sendMessage('What were we talking about?', {
conversationId: res.conversationId,
parentMessageId: res.messageId
})
console.log(res.response)
```
Sometimes, ChatGPT will hang for an extended period of time before beginning to respond. This may be due to rate limiting or it may be due to OpenAI's servers being overloaded.
@ -151,8 +159,6 @@ const response = await api.sendMessage('this is a timeout test', {
})
```
You can stream responses using the `onProgress` or `onConversationResponse` callbacks. See the [docs](./docs/classes/ChatGPTAPI.md) for more details.
<details>
<summary>Usage in CommonJS (Dynamic import)</summary>
@ -167,10 +173,10 @@ async function example() {
})
const api = new ChatGPTAPI({ ...openAIAuth })
await api.ensureAuth()
await api.initSession()
const response = await api.sendMessage('Hello World!')
console.log(response)
const result = await api.sendMessage('Hello World!')
console.log(result)
}
```

Wyświetl plik

@ -0,0 +1,70 @@
import * as types from './types'
export abstract class AChatGPTAPI {
/**
* Performs any async initialization work required to ensure that this API is
* properly authenticated.
*
* @throws An error if the session failed to initialize properly.
*/
abstract initSession(): Promise<void>
/**
* Sends a message to ChatGPT, waits for the response to resolve, and returns
* the response.
*
* If you want to receive a stream of partial responses, use `opts.onProgress`.
*
* @param message - The prompt message to send
* @param opts.conversationId - Optional ID of a conversation to continue
* @param opts.parentMessageId - Optional ID of the previous message in the conversation
* @param opts.messageId - Optional ID of the message to send (defaults to a random UUID)
* @param opts.action - Optional ChatGPT `action` (either `next` or `variant`)
* @param opts.timeoutMs - Optional timeout in milliseconds (defaults to no timeout)
* @param opts.onProgress - Optional callback which will be invoked every time the partial response is updated
* @param opts.abortSignal - Optional callback used to abort the underlying `fetch` call using an [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)
*
* @returns The response from ChatGPT, including `conversationId`, `messageId`, and
* the `response` text.
*/
abstract sendMessage(
message: string,
opts?: types.SendMessageOptions
): Promise<types.ChatResponse>
/**
* @returns `true` if the client is authenticated with a valid session or `false`
* otherwise.
*/
abstract getIsAuthenticated(): Promise<boolean>
/**
* Refreshes the current ChatGPT session.
*
* Useful for bypassing 403 errors when Cloudflare clearance tokens expire.
*
* @returns Access credentials for the new session.
* @throws An error if it fails.
*/
abstract refreshSession(): Promise<any>
/**
* Closes the current ChatGPT session and starts a new one.
*
* Useful for bypassing 401 errors when sessions expire.
*
* @returns Access credentials for the new session.
* @throws An error if it fails.
*/
async resetSession(): Promise<any> {
await this.closeSession()
return this.initSession()
}
/**
* Closes the active session.
*
* @throws An error if it fails.
*/
abstract closeSession(): Promise<void>
}

Wyświetl plik

@ -3,15 +3,19 @@ import type { Browser, HTTPRequest, HTTPResponse, Page } from 'puppeteer'
import { v4 as uuidv4 } from 'uuid'
import * as types from './types'
import { AChatGPTAPI } from './abstract-chatgpt-api'
import { getBrowser, getOpenAIAuth } from './openai-auth'
import {
browserPostEventStream,
isRelevantRequest,
markdownToText,
maximizePage,
minimizePage
} from './utils'
export class ChatGPTAPIBrowser {
const CHAT_PAGE_URL = 'https://chat.openai.com/chat'
export class ChatGPTAPIBrowser extends AChatGPTAPI {
protected _markdown: boolean
protected _debug: boolean
protected _minimize: boolean
@ -27,7 +31,7 @@ export class ChatGPTAPIBrowser {
protected _page: Page
/**
* Creates a new client wrapper for automating the ChatGPT webapp.
* Creates a new client for automating the ChatGPT webapp.
*/
constructor(opts: {
email: string
@ -51,6 +55,8 @@ export class ChatGPTAPIBrowser {
/** @defaultValue `undefined` **/
executablePath?: string
}) {
super()
const {
email,
password,
@ -71,14 +77,23 @@ export class ChatGPTAPIBrowser {
this._minimize = !!minimize
this._captchaToken = captchaToken
this._executablePath = executablePath
if (!this._email) {
const error = new types.ChatGPTError('ChatGPT invalid email')
error.statusCode = 401
throw error
}
if (!this._password) {
const error = new types.ChatGPTError('ChatGPT invalid password')
error.statusCode = 401
throw error
}
}
async init() {
override async initSession() {
if (this._browser) {
await this._browser.close()
this._page = null
this._browser = null
this._accessToken = null
await this.closeSession()
}
try {
@ -89,6 +104,15 @@ export class ChatGPTAPIBrowser {
this._page =
(await this._browser.pages())[0] || (await this._browser.newPage())
// bypass annoying popup modals
this._page.evaluateOnNewDocument(() => {
window.localStorage.setItem('oai/apps/hasSeenOnboarding/chat', 'true')
window.localStorage.setItem(
'oai/apps/hasSeenReleaseAnnouncement/2022-12-15',
'true'
)
})
await maximizePage(this._page)
this._page.on('request', this._onRequest.bind(this))
@ -113,11 +137,8 @@ export class ChatGPTAPIBrowser {
throw err
}
const chatUrl = 'https://chat.openai.com/chat'
const url = this._page.url().replace(/\/$/, '')
if (url !== chatUrl) {
await this._page.goto(chatUrl, {
if (!this.isChatPage) {
await this._page.goto(CHAT_PAGE_URL, {
waitUntil: 'networkidle2'
})
}
@ -140,15 +161,13 @@ export class ChatGPTAPIBrowser {
await delay(300)
} while (true)
if (!this.getIsAuthenticated()) {
return false
if (!(await this.getIsAuthenticated())) {
throw new types.ChatGPTError('Failed to authenticate session')
}
if (this._minimize) {
await minimizePage(this._page)
return minimizePage(this._page)
}
return true
}
_onRequest = (request: HTTPRequest) => {
@ -221,11 +240,13 @@ export class ChatGPTAPIBrowser {
if (url.endsWith('/conversation')) {
if (status === 403) {
await this.handle403Error()
await this.refreshSession()
}
} else if (url.endsWith('api/auth/session')) {
if (status === 403) {
await this.handle403Error()
if (status === 401) {
await this.resetSession()
} else if (status === 403) {
await this.refreshSession()
} else {
const session: types.SessionResult = body
@ -236,17 +257,40 @@ export class ChatGPTAPIBrowser {
}
}
async handle403Error() {
console.log(`ChatGPT "${this._email}" session expired; refreshing...`)
/**
* Attempts to handle 401 errors by re-authenticating.
*/
async resetSession() {
console.log(
`ChatGPT "${this._email}" session expired; re-authenticating...`
)
try {
await this.closeSession()
await this.initSession()
console.log(`ChatGPT "${this._email}" re-authenticated successfully`)
} catch (err) {
console.error(
`ChatGPT "${this._email}" error re-authenticating`,
err.toString()
)
}
}
/**
* Attempts to handle 403 errors by refreshing the page.
*/
async refreshSession() {
console.log(`ChatGPT "${this._email}" session expired (403); refreshing...`)
try {
await maximizePage(this._page)
await this._page.reload({
waitUntil: 'networkidle2',
timeout: 2 * 60 * 1000 // 2 minutes
})
if (this._minimize) {
if (this._minimize && this.isChatPage) {
await minimizePage(this._page)
}
console.log(`ChatGPT "${this._email}" refreshed session successfully`)
} catch (err) {
console.error(
`ChatGPT "${this._email}" error refreshing session`,
@ -257,6 +301,10 @@ export class ChatGPTAPIBrowser {
async getIsAuthenticated() {
try {
if (!this._accessToken) {
return false
}
const inputBox = await this._getInputBox()
return !!inputBox
} catch (err) {
@ -328,28 +376,25 @@ export class ChatGPTAPIBrowser {
// }
// }
async sendMessage(
override async sendMessage(
message: string,
opts: types.SendMessageOptions = {}
): Promise<string> {
): Promise<types.ChatResponse> {
const {
conversationId,
parentMessageId = uuidv4(),
messageId = uuidv4(),
action = 'next',
timeoutMs
// TODO
timeoutMs,
// onProgress,
onConversationResponse
// onProgress
} = opts
const inputBox = await this._getInputBox()
if (!inputBox || !this._accessToken) {
if (!(await this.getIsAuthenticated())) {
console.log(`chatgpt re-authenticating ${this._email}`)
let isAuthenticated = false
try {
isAuthenticated = await this.init()
await this.resetSession()
} catch (err) {
console.warn(
`chatgpt error re-authenticating ${this._email}`,
@ -357,7 +402,7 @@ export class ChatGPTAPIBrowser {
)
}
if (!isAuthenticated || !this._accessToken) {
if (!(await this.getIsAuthenticated())) {
const error = new types.ChatGPTError('Not signed in')
error.statusCode = 401
throw error
@ -395,25 +440,24 @@ export class ChatGPTAPIBrowser {
)
// console.log('<<< EVALUATE', result)
if (result.error) {
if ('error' in result) {
const error = new types.ChatGPTError(result.error.message)
error.statusCode = result.error.statusCode
error.statusText = result.error.statusText
if (error.statusCode === 403) {
await this.handle403Error()
await this.refreshSession()
}
throw error
}
} else {
if (!this._markdown) {
result.response = markdownToText(result.response)
}
// TODO: support sending partial response events
if (onConversationResponse) {
onConversationResponse(result.conversationResponse)
return result
}
return result.response
// const lastMessage = await this.getLastMessage()
// await inputBox.focus()
@ -465,14 +509,24 @@ export class ChatGPTAPIBrowser {
}
}
async close() {
override async closeSession() {
await this._browser.close()
this._page = null
this._browser = null
this._accessToken = null
}
protected async _getInputBox() {
// [data-id="root"]
return this._page.$('textarea')
}
get isChatPage(): boolean {
try {
const url = this._page?.url().replace(/\/$/, '')
return url === CHAT_PAGE_URL
} catch (err) {
return false
}
}
}

Wyświetl plik

@ -21,7 +21,7 @@ test('ChatGPTAPI invalid session token', async (t) => {
sessionToken: 'invalid',
clearanceToken: 'invalid'
})
await chatgpt.ensureAuth()
await chatgpt.initSession()
},
{
instanceOf: types.ChatGPTError,
@ -52,7 +52,7 @@ test('ChatGPTAPI valid session token', async (t) => {
// Don't make any real API calls using our session token if we're running on CI
if (!isCI) {
await chatgpt.ensureAuth()
await chatgpt.initSession()
const response = await chatgpt.sendMessage('test')
console.log('chatgpt response', response)
@ -74,7 +74,7 @@ if (!isCI) {
sessionToken: expiredSessionToken,
clearanceToken: 'invalid'
})
await chatgpt.ensureAuth()
await chatgpt.initSession()
},
{
instanceOf: types.ChatGPTError,

Wyświetl plik

@ -3,7 +3,7 @@ import pTimeout from 'p-timeout'
import { v4 as uuidv4 } from 'uuid'
import * as types from './types'
import { ChatGPTConversation } from './chatgpt-conversation'
import { AChatGPTAPI } from './abstract-chatgpt-api'
import { fetch } from './fetch'
import { fetchSSE } from './fetch-sse'
import { markdownToText } from './utils'
@ -12,7 +12,7 @@ const KEY_ACCESS_TOKEN = 'accessToken'
const USER_AGENT =
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36'
export class ChatGPTAPI {
export class ChatGPTAPI extends AChatGPTAPI {
protected _sessionToken: string
protected _clearanceToken: string
protected _markdown: boolean
@ -71,6 +71,8 @@ export class ChatGPTAPI {
/** @defaultValue `false` **/
debug?: boolean
}) {
super()
const {
sessionToken,
clearanceToken,
@ -113,11 +115,15 @@ export class ChatGPTAPI {
}
if (!this._sessionToken) {
throw new types.ChatGPTError('ChatGPT invalid session token')
const error = new types.ChatGPTError('ChatGPT invalid session token')
error.statusCode = 401
throw error
}
if (!this._clearanceToken) {
throw new types.ChatGPTError('ChatGPT invalid clearance token')
const error = new types.ChatGPTError('ChatGPT invalid clearance token')
error.statusCode = 401
throw error
}
}
@ -143,6 +149,14 @@ export class ChatGPTAPI {
return this._userAgent
}
/**
* Refreshes the client's access token which will succeed only if the session
* is valid.
*/
override async initSession() {
await this.refreshSession()
}
/**
* Sends a message to ChatGPT, waits for the response to resolve, and returns
* the response.
@ -159,23 +173,21 @@ export class ChatGPTAPI {
* @param opts.action - Optional ChatGPT `action` (either `next` or `variant`)
* @param opts.timeoutMs - Optional timeout in milliseconds (defaults to no timeout)
* @param opts.onProgress - Optional callback which will be invoked every time the partial response is updated
* @param opts.onConversationResponse - Optional callback which will be invoked every time the partial response is updated with the full conversation response
* @param opts.abortSignal - Optional callback used to abort the underlying `fetch` call using an [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)
*
* @returns The response from ChatGPT
*/
async sendMessage(
override async sendMessage(
message: string,
opts: types.SendMessageOptions = {}
): Promise<string> {
): Promise<types.ChatResponse> {
const {
conversationId,
parentMessageId = uuidv4(),
messageId = uuidv4(),
action = 'next',
timeoutMs,
onProgress,
onConversationResponse
onProgress
} = opts
let { abortSignal } = opts
@ -186,7 +198,7 @@ export class ChatGPTAPI {
abortSignal = abortController.signal
}
const accessToken = await this.refreshAccessToken()
const accessToken = await this.refreshSession()
const body: types.ConversationJSONBody = {
action,
@ -208,9 +220,13 @@ export class ChatGPTAPI {
body.conversation_id = conversationId
}
let response = ''
const result: types.ChatResponse = {
conversationId,
messageId,
response: ''
}
const responseP = new Promise<string>((resolve, reject) => {
const responseP = new Promise<types.ChatResponse>((resolve, reject) => {
const url = `${this._backendApiBaseUrl}/conversation`
const headers = {
...this._headers,
@ -231,17 +247,22 @@ export class ChatGPTAPI {
signal: abortSignal,
onMessage: (data: string) => {
if (data === '[DONE]') {
return resolve(response)
return resolve(result)
}
try {
const parsedData: types.ConversationResponseEvent = JSON.parse(data)
if (onConversationResponse) {
onConversationResponse(parsedData)
const convoResponseEvent: types.ConversationResponseEvent =
JSON.parse(data)
if (convoResponseEvent.conversation_id) {
result.conversationId = convoResponseEvent.conversation_id
}
const message = parsedData.message
// console.log('event', JSON.stringify(parsedData, null, 2))
if (convoResponseEvent.message?.id) {
result.messageId = convoResponseEvent.message.id
}
const message = convoResponseEvent.message
// console.log('event', JSON.stringify(convoResponseEvent, null, 2))
if (message) {
let text = message?.content?.parts?.[0]
@ -251,10 +272,10 @@ export class ChatGPTAPI {
text = markdownToText(text)
}
response = text
result.response = text
if (onProgress) {
onProgress(text)
onProgress(result)
}
}
}
@ -267,7 +288,7 @@ export class ChatGPTAPI {
const errMessageL = err.toString().toLowerCase()
if (
response &&
result.response &&
(errMessageL === 'error: typeerror: terminated' ||
errMessageL === 'typeerror: terminated')
) {
@ -275,7 +296,7 @@ export class ChatGPTAPI {
// the HTTP request has resolved cleanly. In my testing, these cases tend to
// happen when OpenAI has already send the last `response`, so we can ignore
// the `fetch` error in this case.
return resolve(response)
return resolve(result)
} else {
return reject(err)
}
@ -301,7 +322,7 @@ export class ChatGPTAPI {
}
async sendModeration(input: string) {
const accessToken = await this.refreshAccessToken()
const accessToken = await this.refreshSession()
const url = `${this._backendApiBaseUrl}/moderations`
const headers = {
...this._headers,
@ -343,23 +364,15 @@ export class ChatGPTAPI {
* @returns `true` if the client has a valid acces token or `false` if refreshing
* the token fails.
*/
async getIsAuthenticated() {
override async getIsAuthenticated() {
try {
void (await this.refreshAccessToken())
void (await this.refreshSession())
return true
} catch (err) {
return false
}
}
/**
* Refreshes the client's access token which will succeed only if the session
* is still valid.
*/
async ensureAuth() {
return await this.refreshAccessToken()
}
/**
* Attempts to refresh the current access token using the ChatGPT
* `sessionToken` cookie.
@ -370,7 +383,7 @@ export class ChatGPTAPI {
* @returns A valid access token
* @throws An error if refreshing the access token fails.
*/
async refreshAccessToken(): Promise<string> {
override async refreshSession(): Promise<string> {
const cachedAccessToken = this._accessTokenCache.get(KEY_ACCESS_TOKEN)
if (cachedAccessToken) {
return cachedAccessToken
@ -454,17 +467,7 @@ export class ChatGPTAPI {
}
}
/**
* Gets a new ChatGPTConversation instance, which can be used to send multiple
* messages as part of a single conversation.
*
* @param opts.conversationId - Optional ID of the previous message in a conversation
* @param opts.parentMessageId - Optional ID of the previous message in a conversation
* @returns The new conversation instance
*/
getConversation(
opts: { conversationId?: string; parentMessageId?: string } = {}
) {
return new ChatGPTConversation(this, opts)
override async closeSession(): Promise<void> {
this._accessTokenCache.delete(KEY_ACCESS_TOKEN)
}
}

Wyświetl plik

@ -1,73 +0,0 @@
import * as types from './types'
import { type ChatGPTAPI } from './chatgpt-api'
/**
* A conversation wrapper around the ChatGPTAPI. This allows you to send
* multiple messages to ChatGPT and receive responses, without having to
* manually pass the conversation ID and parent message ID for each message.
*/
export class ChatGPTConversation {
api: ChatGPTAPI
conversationId: string = undefined
parentMessageId: string = undefined
/**
* Creates a new conversation wrapper around the ChatGPT API.
*
* @param api - The ChatGPT API instance to use
* @param opts.conversationId - Optional ID of a conversation to continue
* @param opts.parentMessageId - Optional ID of the previous message in the conversation
*/
constructor(
api: ChatGPTAPI,
opts: { conversationId?: string; parentMessageId?: string } = {}
) {
this.api = api
this.conversationId = opts.conversationId
this.parentMessageId = opts.parentMessageId
}
/**
* Sends a message to ChatGPT, waits for the response to resolve, and returns
* the response.
*
* If this is the first message in the conversation, the conversation ID and
* parent message ID will be automatically set.
*
* This allows you to send multiple messages to ChatGPT and receive responses,
* without having to manually pass the conversation ID and parent message ID
* for each message.
*
* @param message - The prompt message to send
* @param opts.onProgress - Optional callback which will be invoked every time the partial response is updated
* @param opts.onConversationResponse - Optional callback which will be invoked every time the partial response is updated with the full conversation response
* @param opts.abortSignal - Optional callback used to abort the underlying `fetch` call using an [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)
*
* @returns The response from ChatGPT
*/
async sendMessage(
message: string,
opts: types.SendConversationMessageOptions = {}
): Promise<string> {
const { onConversationResponse, ...rest } = opts
return this.api.sendMessage(message, {
...rest,
conversationId: this.conversationId,
parentMessageId: this.parentMessageId,
onConversationResponse: (response) => {
if (response.conversation_id) {
this.conversationId = response.conversation_id
}
if (response.message?.id) {
this.parentMessageId = response.message.id
}
if (onConversationResponse) {
return onConversationResponse(response)
}
}
})
}
}

Wyświetl plik

@ -1,6 +1,6 @@
export * from './chatgpt-api'
export * from './chatgpt-api-browser'
export * from './chatgpt-conversation'
export * from './abstract-chatgpt-api'
export * from './types'
export * from './utils'
export * from './openai-auth'

Wyświetl plik

@ -1,7 +1,10 @@
import * as fs from 'node:fs'
import * as os from 'node:os'
import * as path from 'node:path'
import * as url from 'node:url'
import delay from 'delay'
import { TimeoutError } from 'p-timeout'
import type { Browser, Page, Protocol, PuppeteerLaunchOptions } from 'puppeteer'
import puppeteer from 'puppeteer-extra'
import RecaptchaPlugin from 'puppeteer-extra-plugin-recaptcha'
@ -12,6 +15,10 @@ import * as types from './types'
puppeteer.use(StealthPlugin())
let hasRecaptchaPlugin = false
let hasNopechaExtension = false
const __filename = url.fileURLToPath(import.meta.url)
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
/**
* Represents everything that's required to pass into `ChatGPTAPI` in order
@ -122,13 +129,21 @@ export async function getOpenAIAuth({
await page.type('#username', email, { delay: 20 })
await delay(100)
if (hasRecaptchaPlugin) {
// console.log('solveRecaptchas()')
if (hasNopechaExtension) {
await waitForRecaptcha(page, { timeoutMs })
} else if (hasRecaptchaPlugin) {
const res = await page.solveRecaptchas()
// console.log('solveRecaptchas result', res)
console.log('solveRecaptchas result', res)
}
await page.click('button[type="submit"]')
await delay(1200)
const frame = page.mainFrame()
const submit = await page.waitForSelector('button[type="submit"]', {
timeout: timeoutMs
})
frame.focus('button[type="submit"]')
await submit.focus()
await submit.click()
await page.waitForSelector('#password', { timeout: timeoutMs })
await page.type('#password', password, { delay: 10 })
submitP = () => page.click('button[type="submit"]')
@ -186,10 +201,12 @@ export async function getOpenAIAuth({
export async function getBrowser(
opts: PuppeteerLaunchOptions & {
captchaToken?: string
nopechaKey?: string
} = {}
) {
const {
captchaToken = process.env.CAPTCHA_TOKEN,
nopechaKey = process.env.NOPECHA_KEY,
executablePath = defaultChromeExecutablePath(),
...launchOptions
} = opts
@ -209,13 +226,71 @@ export async function getBrowser(
)
}
return puppeteer.launch({
const puppeteerArgs = [
'--no-sandbox',
'--disable-infobars',
'--disable-dev-shm-usage',
'--disable-blink-features=AutomationControlled',
'--no-first-run',
'--no-service-autorun',
'--password-store=basic',
'--system-developer-mode'
]
if (nopechaKey) {
const nopechaPath = path.join(
__dirname,
'..',
'third-party',
'nopecha-chrome-extension'
)
puppeteerArgs.push(`--disable-extensions-except=${nopechaPath}`)
puppeteerArgs.push(`--load-extension=${nopechaPath}`)
hasNopechaExtension = true
}
const browser = await puppeteer.launch({
headless: false,
args: ['--no-sandbox', '--exclude-switches', 'enable-automation'],
// https://peter.sh/experiments/chromium-command-line-switches/
args: puppeteerArgs,
ignoreDefaultArgs: [
'--disable-extensions',
'--enable-automation',
'--disable-component-extensions-with-background-pages'
],
ignoreHTTPSErrors: true,
executablePath,
...launchOptions
})
// TOdO: this is a really hackity hack way of setting the API key...
if (hasNopechaExtension) {
const page = (await browser.pages())[0] || (await browser.newPage())
await page.goto(`https://nopecha.com/setup#${nopechaKey}`)
await delay(1000)
const page3 = await browser.newPage()
await page.close()
const extensionId = 'npgnhlnhpphdlkfdnggbdpbhoopefaai'
const extensionUrl = `chrome-extension://${extensionId}/popup.html`
await page3.goto(extensionUrl, { waitUntil: 'networkidle2' })
await delay(500)
const editKey = await page3.waitForSelector('#edit_key .clickable')
await editKey.click()
const settingsInput = await page3.$('input.settings_text')
await settingsInput.type(nopechaKey)
await settingsInput.evaluate((el, value) => {
el.value = value
}, nopechaKey)
await settingsInput.press('Enter')
await delay(500)
await editKey.click()
await delay(2000)
}
return browser
}
/**
@ -249,13 +324,6 @@ async function checkForChatGPTAtCapacity(page: Page) {
try {
res = await page.$x("//div[contains(., 'ChatGPT is at capacity')]")
// console.log('capacity1', els)
// if (els?.length) {
// res = await Promise.all(
// els.map((a) => a.evaluate((el) => el.textContent))
// )
// console.log('capacity2', res)
// }
} catch (err) {
// ignore errors likely due to navigation
}
@ -315,3 +383,40 @@ async function waitForConditionOrAtCapacity(
setTimeout(waitForCapacityText, pollingIntervalMs)
})
}
async function waitForRecaptcha(
page: Page,
opts: {
pollingIntervalMs?: number
timeoutMs?: number
} = {}
) {
if (!hasNopechaExtension) {
return
}
const { pollingIntervalMs = 100, timeoutMs } = opts
const captcha = await page.$('textarea#g-recaptcha-response')
const startTime = Date.now()
if (captcha) {
console.log('waiting to solve recaptcha...')
do {
const value = (await captcha.evaluate((el) => el.value))?.trim()
if (value?.length) {
// recaptcha has been solved!
break
}
if (timeoutMs) {
const now = Date.now()
if (now - startTime >= timeoutMs) {
throw new TimeoutError('Timed out waiting to solve Recaptcha')
}
}
await delay(pollingIntervalMs)
} while (true)
}
}

Wyświetl plik

@ -281,8 +281,7 @@ export type SendMessageOptions = {
messageId?: string
action?: MessageActionType
timeoutMs?: number
onProgress?: (partialResponse: string) => void
onConversationResponse?: (response: ConversationResponseEvent) => void
onProgress?: (partialResponse: ChatResponse) => void
abortSignal?: AbortSignal
}
@ -300,16 +299,12 @@ export class ChatGPTError extends Error {
export type ChatError = {
error: { message: string; statusCode?: number; statusText?: string }
response: null
conversationId?: string
messageId?: string
conversationResponse?: ConversationResponseEvent
}
export type ChatResponse = {
error: null
response: string
conversationId: string
messageId: string
conversationResponse?: ConversationResponseEvent
}

Wyświetl plik

@ -37,7 +37,7 @@ export async function maximizePage(page: Page) {
}
export function isRelevantRequest(url: string): boolean {
let pathname
let pathname: string
try {
const parsedUrl = new URL(url)
@ -102,7 +102,6 @@ export async function browserPostEventStream(
const BOM = [239, 187, 191]
let conversationResponse: types.ConversationResponseEvent
let conversationId: string = body?.conversation_id
let messageId: string = body?.messages?.[0]?.id
let response = ''
@ -136,7 +135,6 @@ export async function browserPostEventStream(
statusCode: res.status,
statusText: res.statusText
},
response: null,
conversationId,
messageId
}
@ -147,18 +145,15 @@ export async function browserPostEventStream(
function onMessage(data: string) {
if (data === '[DONE]') {
return resolve({
error: null,
response,
conversationId,
messageId,
conversationResponse
messageId
})
}
try {
const convoResponseEvent: types.ConversationResponseEvent =
JSON.parse(data)
conversationResponse = convoResponseEvent
if (convoResponseEvent.conversation_id) {
conversationId = convoResponseEvent.conversation_id
}
@ -220,11 +215,9 @@ export async function browserPostEventStream(
// happen when OpenAI has already send the last `response`, so we can ignore
// the `fetch` error in this case.
return {
error: null,
response,
conversationId,
messageId,
conversationResponse
messageId
}
}
@ -234,10 +227,8 @@ export async function browserPostEventStream(
statusCode: err.statusCode || err.status || err.response?.statusCode,
statusText: err.statusText || err.response?.statusText
},
response: null,
conversationId,
messageId,
conversationResponse
messageId
}
}
@ -456,7 +447,7 @@ export async function browserPostEventStream(
customTimers = { setTimeout, clearTimeout }
} = options
let timer
let timer: number
const cancelablePromise = new Promise((resolve, reject) => {
if (typeof milliseconds !== 'number' || Math.sign(milliseconds) !== 1) {

Wyświetl plik

@ -0,0 +1 @@
const VERSION="chrome",browser=globalThis.chrome;function reconnect_scripts(){browser.runtime.onInstalled.addListener(async()=>{for(const e of browser.runtime.getManifest().content_scripts)for(const r of await browser.tabs.query({url:e.matches}))browser.scripting.executeScript({target:{tabId:r.id},files:e.js})})}function register_language(){browser.declarativeNetRequest.updateDynamicRules({addRules:[{id:1,priority:1,action:{type:"redirect",redirect:{transform:{queryTransform:{addOrReplaceParams:[{key:"hl",value:"en-US"}]}}}},condition:{regexFilter:"^(http|https)://[^\\.]*\\.(google\\.com|recaptcha\\.net)/recaptcha",resourceTypes:["sub_frame"]}},{id:2,priority:1,action:{type:"redirect",redirect:{transform:{queryTransform:{addOrReplaceParams:[{key:"lang",value:"en"}]}}}},condition:{regexFilter:"^(http|https)://[^\\.]*\\.(funcaptcha\\.(co|com)|arkoselabs\\.(com|cn)|arkose\\.com\\.cn)",resourceTypes:["sub_frame"]}}],removeRuleIds:[1,2]})}export{VERSION,browser,reconnect_scripts,register_language};

Wyświetl plik

@ -0,0 +1 @@
(async()=>{let i=null;function a(a=500){return new Promise(t=>{let c=!1;const n=setInterval(async()=>{if(!c){c=!0;var a=await BG.exec("Settings.get");if(a.enabled&&a.awscaptcha_auto_solve){a=document.querySelector('input[placeholder="Answer"]');if(a&&""===a.value){var e=function(){try{return document.querySelector("audio").src.replace("data:audio/aac;base64,","")}catch(a){}return null}();if(e&&i!==e)return i=e,clearInterval(n),c=!1,t({input:a,audio_data:e})}c=!1}}},a)})}for(;;){await Time.sleep(1e3);var e=await BG.exec("Settings.get");if(e&&e.enabled){var t,c,n,o,l=await Location.hostname();if(!e.disabled_hosts.includes(l))if(e.awscaptcha_auto_open&&null!==document.querySelector("#captcha-container > #root #amzn-captcha-verify-button")){l=void 0;try{var l=document.querySelector("#captcha-container > #root #amzn-captcha-verify-button");l&&l.click()}catch(a){}await 0}else if(e.hcaptcha_auto_solve&&null!==document.querySelector('#captcha-container > #root #amzn-btn-audio-internal > img[title="Audio problem"]')){l=void 0;try{l=document.querySelector("#captcha-container > #root #amzn-btn-audio-internal");l&&l.click()}catch(a){}await 0}else e.hcaptcha_auto_solve&&null!==document.querySelector('#captcha-container > #root #amzn-btn-audio-internal > img[title="Visual problem"]')&&(n=c=t=o=e=l=void 0,{input:l,audio_data:e}=await a(),await!(null!==l&&null!==e&&(o=await BG.exec("Settings.get")).enabled&&o.awscaptcha_auto_solve&&(t=Time.time(),{job_id:c,data:e}=await NopeCHA.post({captcha_type:IS_DEVELOPMENT?"awscaptcha_dev":"awscaptcha",audio_data:[e],key:o.key}),!e||0===e.length||(n=(n=parseInt(o.awscaptcha_solve_delay_time))||1e3,0<(o=o.awscaptcha_solve_delay?n-(Time.time()-t):0)&&await Time.sleep(o),0===e[0].length)?(document.querySelector("#amzn-btn-refresh-internal")?.click(),await Time.sleep(200),i=null):(l.value=e[0],await Time.sleep(200),document.querySelector("#amzn-btn-verify-internal")?.click()))))}}})();

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -0,0 +1,151 @@
class BG {
static exec() {
return new Promise((a) => {
try {
chrome.runtime.sendMessage([...arguments], a)
} catch (e) {
a(null)
}
})
}
}
class Net {
static async fetch(e, a) {
return BG.exec('Net.fetch', { url: e, options: a })
}
}
class Script {
static inject_file(t) {
return new Promise((e) => {
var a = document.createElement('script')
;(a.src = chrome.runtime.getURL(t)),
(a.onload = e),
(document.head || document.documentElement).appendChild(a)
})
}
}
class Location {
static parse_hostname(e) {
return e.replace(/^(.*:)\/\/([A-Za-z0-9\-\.]+)(:[0-9]+)?(.*)$/, '$2')
}
static async hostname() {
var e = await BG.exec('Tab.info'),
e = e.url || 'Unknown Host'
return Location.parse_hostname(e)
}
}
class Image {
static encode(a) {
return new Promise((t) => {
if (null === a) return t(null)
const e = new XMLHttpRequest()
;(e.onload = () => {
const a = new FileReader()
;(a.onloadend = () => {
let e = a.result
if (e.startsWith('data:text/html;base64,')) return t(null)
;(e = e.replace('data:image/jpeg;base64,', '')), t(e)
}),
a.readAsDataURL(e.response)
}),
(e.onerror = () => {
t(null)
}),
(e.onreadystatechange = () => {
4 == this.readyState && 200 != this.status && t(null)
}),
e.open('GET', a),
(e.responseType = 'blob'),
e.send()
})
}
}
class NopeCHA {
static INFERENCE_URL = 'https://api.nopecha.com'
static MAX_WAIT_POST = 60
static MAX_WAIT_GET = 60
static ERRORS = {
UNKNOWN: 9,
INVALID_REQUEST: 10,
RATE_LIIMTED: 11,
BANNED_USER: 12,
NO_JOB: 13,
INCOMPLETE_JOB: 14,
INVALID_KEY: 15,
NO_CREDIT: 16,
UPDATE_REQUIRED: 17
}
static async post({
captcha_type: e,
task: a,
image_urls: t,
image_data: r,
grid: n,
audio_data: o,
key: i
}) {
for (
var s = Date.now(), c = await BG.exec('Tab.info');
!(Date.now() - s > 1e3 * NopeCHA.MAX_WAIT_POST);
) {
var d = {
type: e,
task: a,
key: i,
v: chrome.runtime.getManifest().version,
url: c ? c.url : window.location.href
}
t && (d.image_urls = t),
r && (d.image_data = r),
n && (d.grid = n),
o && (d.audio_data = o)
try {
var l = { 'Content-Type': 'application/json' },
u =
(i && 'undefined' !== i && (l.Authorization = 'Bearer ' + i),
await Net.fetch(NopeCHA.INFERENCE_URL, {
method: 'POST',
headers: l,
body: JSON.stringify(d)
})),
p = JSON.parse(u)
if (!p) {
break
}
if ('error' in p) {
if (p.error === NopeCHA.ERRORS.RATE_LIMITED) {
await Time.sleep(2e3)
continue
}
if (p.error === NopeCHA.ERRORS.INVALID_KEY) break
if (p.error === NopeCHA.ERRORS.NO_CREDIT) break
break
}
var _ = p.data
return await NopeCHA.get({ job_id: _, key: i })
} catch (e) {}
await Time.sleep(1e3)
}
return { job_id: null, data: null }
}
static async get({ job_id: e, key: a }) {
for (var t = Date.now(); !(Date.now() - t > 1e3 * NopeCHA.MAX_WAIT_GET); ) {
await Time.sleep(1e3)
var r = {},
r =
(a && 'undefined' !== a && (r.Authorization = 'Bearer ' + a),
await Net.fetch(NopeCHA.INFERENCE_URL + `?id=${e}&key=` + a, {
headers: r
}))
try {
var n = JSON.parse(r)
if (!('error' in n))
return { job_id: e, data: n.data, metadata: n.metadata }
if (n.error !== NopeCHA.ERRORS.INCOMPLETE_JOB)
return { job_id: e, data: null, metadata: null }
} catch (e) {}
}
return { job_id: e, data: null, metadata: null }
}
}

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -0,0 +1 @@
(async()=>{function o(){return null!==(document.querySelector('button[aria-describedby="descriptionVerify"]')||document.querySelector("#wrong_children_button")||document.querySelector("#wrongTimeout_children_button"))}function r(){try{var e=document.querySelector('button[aria-describedby="descriptionVerify"]'),t=(e&&(window.parent.postMessage({nopecha:!0,action:"clear"},"*"),e.click()),document.querySelector("#wrong_children_button")),a=(t&&(window.parent.postMessage({nopecha:!0,action:"clear"},"*"),t.click()),document.querySelector("#wrongTimeout_children_button"));a&&(window.parent.postMessage({nopecha:!0,action:"clear"},"*"),a.click())}catch(e){}}function u(){return document.querySelector("#game_children_text > h2")?.innerText?.trim()}function s(){return document.querySelector("img#game_challengeItem_image")?.src?.split(";base64,")[1]}let d=null;async function e(){e=500;var e,{task:t,cells:a,image_data:n}=await new Promise(n=>{let c=!1;const i=setInterval(async()=>{if(!c){c=!0;var e=await BG.exec("Settings.get");if(e.enabled&&e.funcaptcha_auto_solve){e.funcaptcha_auto_open&&o()&&await r();e=u();if(e){var t=document.querySelectorAll("#game_children_challenge ul > li > a");if(6===t.length){var a=s();if(a&&d!==a)return d=a,clearInterval(i),c=!1,n({task:e,cells:t,image_data:a})}}c=!1}}},e)});if(null!==t&&null!==a&&null!==n){var c=await BG.exec("Settings.get");if(c.enabled&&c.funcaptcha_auto_solve){var i=Time.time(),l=(await NopeCHA.post({captcha_type:IS_DEVELOPMENT?"funcaptcha_dev":"funcaptcha",task:t,image_data:[n],key:c.key}))["data"];if(l){t=parseInt(c.funcaptcha_solve_delay_time)||1e3,n=c.funcaptcha_solve_delay?t-(Time.time()-i):0;0<n&&await Time.sleep(n);for(let e=0;e<l.length;e++)!1!==l[e]&&a[e].click()}d=null}}}if(window.location.pathname.startsWith("/fc/assets/tile-game-ui/"))for(;;){await Time.sleep(1e3);var t,a=await BG.exec("Settings.get");a&&a.enabled&&(t=await Location.hostname(),a.disabled_hosts.includes(t)||(a.funcaptcha_auto_open&&o()?await r():a.funcaptcha_auto_solve&&null!==u()&&null!==s()&&await e()))}})();

Wyświetl plik

@ -0,0 +1,63 @@
(async()=>{const u={linkedin:["3117BF26-4762-4F5A-8ED9-A85E69209A46",!1],rockstar:["A5A70501-FCDE-4065-AF18-D9FAF06EF479",!1],github:["20782B4C-05D0-45D7-97A0-41641055B6F6",!1],paypal:["9409E63B-D2A5-9CBD-DBC0-5095707D0090",!1],blizzard:["E8A75615-1CBA-5DFF-8032-D16BCF234E10",!1],twitch:["E5554D43-23CC-1982-971D-6A2262A2CA24",!1],demo1:["804380F4-6844-FFA1-ED4E-5877CA1F1EA4",!1],demo2:["D39B0EE3-2973-4147-98EF-C92F93451E2D",!1],"ea signup":["73BEC076-3E53-30F5-B1EB-84F494D43DBA",!1],"ea signin":["0F5FE186-B3CA-4EDB-A39B-9B9A3397D01D",!1],myprepaidcenter:["0F941BF0-7303-D94B-B76A-EAA2E2048124",!1],twitter:["2CB16598-CB82-4CF7-B332-5990DB66F3AB",!0],discoveryplus:["FE296399-FDEA-2EA2-8CD5-50F6E3157ECA",!1],minecraft:["D39B0EE3-2973-4147-98EF-C92F93451E2D",!1],imvu:["0C2B415C-D772-47D4-A183-34934F786C7E",!1],adobe:["430FF2C3-1AB1-40B7-8BE7-44FC683FE02C",!1]},h={outlook:["https://iframe.arkoselabs.com/B7D8911C-5CC8-A9A3-35B0-554ACEE604DA/index.html?mkt=en",!1],"outlook auth":["https://iframe-auth.arkoselabs.com/B7D8911C-5CC8-A9A3-35B0-554ACEE604DA/index.html?mkt=en",!1]};let E=18;function w(){g("linkedin",0,1),g("rockstar",0,1),g("demo1",0,1),g("blizzard",0,1),g("twitch",0,1),g("paypal",0,1),A("outlook auth",0,1),g("github",0,1),g("demo2",0,1),A("outlook",0,1),g("ea signup",0,1),g("ea signin",0,1),g("twitter",0,1),g("minecraft",0,1),g("imvu",0,1),g("adobe",0,1)}function g(t,o,n){n=n||E;for(let e=0;e<n;e++)!async function(e,t){var o=u[e][0],n="https://api.funcaptcha.com/fc/gt2/public_key/"+o,n=await Net.fetch(n,{headers:{accept:"*/*","accept-language":"en-US,en;q=0.9","cache-control":"no-cache","content-type":"application/x-www-form-urlencoded; charset=UTF-8",pragma:"no-cache","sec-ch-ua":'"Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"',"sec-ch-ua-mobile":"?0","sec-ch-ua-platform":'"Linux"',"sec-fetch-dest":"empty","sec-fetch-mode":"cors","sec-fetch-site":"cross-site"},referrer:"",referrerPolicy:"strict-origin-when-cross-origin",body:`bda=&public_key=${o}&site=${encodeURIComponent("")}&language=en&userbrowser=Mozilla%2F5.0%20(X11%3B%20Linux%20x86_64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F105.0.0.0%20Safari%2F537.36&rnd=`+Math.random(),method:"POST",mode:"cors",credentials:"omit"}),o=JSON.parse(n),r={};for(const i of o.token.split("|")){var a=i.split("=");let e=a[0],t=a[1];a[1]||(e="token",t=a[0]),e.endsWith("url")&&(t=decodeURIComponent(t)),r[e]=t}n=new URLSearchParams(r).toString(),o="https://api.funcaptcha.com/fc/gc/?"+n;c(e,t,o,u[e][1])}(t,o)}function A(t,o,n){n=n||E;for(let e=0;e<n;e++)c(t,o,h[t][0],h[t][1])}function c(e,t,o,n=!1){var r=document.createElement("div"),a=(r.classList.add("iframe_wrap"),document.createElement("iframe"));n&&a.classList.add("small"),r.append(a),a.frameborder=0,a.scrolling="no",a.src=o;let i=document.querySelector("#iframe_row_"+t);i||((i=document.createElement("div")).classList.add("iframe_row"),i.id="iframe_row_"+t,document.body.append(i));n=document.createElement("div"),n.classList.add("name"),n.innerHTML=e,a=document.createElement("div");a.append(n),a.append(r),i.append(a)}!function e(){document.body.innerHTML="";const t=[`body, html {
background-color: #212121;
}`,`.input_row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}`,`.input_row > * {
height: 20px;
line-height: 20px;
padding: 0;
border: 0;
font-size: 12px;
}`,`.input_row > input[type="button"] {
width: 100px;
cursor: pointer;
transition: 200ms all;
}`,`.input_row > input[type="button"]:hover {
opacity: 0.8;
}`,`#nframes_label {
background-color: #fff;
color: #222;
width: 70px;
text-align: center;
}`,`#nframes, #nframes:active {
width: 30px;
border: none;
outline: none;
}`,`.name {
color: #fff;
}`,`.iframe_row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}`,`.iframe_wrap {
background-color: #eee;
width: 275px;
height: 275px;
padding: 0;
overflow: hidden;
}`,`iframe {
border: none !important;
width: 400px !important;
height: 400px !important;
-ms-zoom: 0.75 !important;
-moz-transform: scale(0.75) !important;
-moz-transform-origin: 0 0 !important;
-o-transform: scale(0.75) !important;
-o-transform-origin: 0 0 !important;
-webkit-transform: scale(0.75) !important;
-webkit-transform-origin: 0 0 !important;
}`,`iframe.small {
width: 550px !important;
height: 550px !important;
-ms-zoom: 0.5 !important;
-moz-transform: scale(0.5) !important;
-moz-transform-origin: 0 0 !important;
-o-transform: scale(0.5) !important;
-o-transform-origin: 0 0 !important;
-webkit-transform: scale(0.5) !important;
-webkit-transform-origin: 0 0 !important;
}`];const o=document.body.appendChild(document.createElement("style")).sheet;for(const n in t)o.insertRule(t[n],n);let n=0;let r=1;const a={};a[0]=document.createElement("div");a[0].classList.add("input_row");document.body.append(a[0]);const i=document.createElement("div");i.id="nframes_label";i.innerText="# iframes";a[0].append(i);const c=document.createElement("input");c.id="nframes";c.placeholder="Number of iframes";c.value=E;c.addEventListener("input",()=>{E=parseInt(c.value)});a[0].append(c);const m={reset:{row:0,fn:e,args:[]},all:{row:0,fn:w,args:[]}};for(const s in u)n++%9==0&&r++,m[s]={row:r,fn:g,args:[s,0]};for(const d in h)n++%9==0&&r++,m[d]={row:r,fn:A,args:[d,0]};for(const[p,l]of Object.entries(m)){const r=l.row,f=(l.row in a||(a[l.row]=document.createElement("div"),a[l.row].classList.add("input_row"),document.body.append(a[l.row])),document.createElement("input"));f.type="button",f.value=p,f.addEventListener("click",()=>{e(),l.fn(...l.args)}),a[l.row].append(f)}}(),g("imvu",0,E)})();

Wyświetl plik

@ -0,0 +1 @@
(async()=>{window.addEventListener("load",()=>{var t=document.body.appendChild(document.createElement("style")).sheet;t.insertRule("* {transition-duration: 0s !important}",0),t.insertRule("li > a::after {border: 8px solid rgba(0, 255, 0, 0.6) !important}",1),t.insertRule("#interstitial {backdrop-filter: none !important}",2),t.insertRule("#interstitial {background-color: transparent !important}",3),t.insertRule("#interstitial_wrapper {background-color: transparent !important}",4)})})();

Wyświetl plik

@ -0,0 +1 @@
(async()=>{var e=IS_DEVELOPMENT;const o="lazy";window.nopecha=[];var a={};async function t(e){var a=(document.querySelector("#game_children_text > h2")||document.querySelector("#game-header"))?.innerText?.trim(),t=(document.querySelector("img#game_challengeItem_image")||document.querySelector("#challenge-image"))?.src?.split(";base64,")[1];a&&t&&(a={task:a,image:t,index:e,url:(await BG.exec("Tab.info"))?.url},o.startsWith("l")&&window.parent.postMessage({nopecha:!0,action:"append",data:a},"*"),o.startsWith("e"))&&await Net.fetch("https://api.nopecha.com/upload",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)})}var n=window.addEventListener?"addEventListener":"attachEvent";for(window[n]("attachEvent"==n?"onmessage":"message",async e=>{e=e[e.message?"message":"data"];e&&!0===e.nopecha&&("append"===e.action?window.nopecha.push(e.data):"clear"===e.action?window.nopecha=[]:"reload"===e.action&&(window.parent.postMessage({nopecha:!0,action:"reload"},"*"),window.location.reload(!0)))},!1);;){await Time.sleep(1e3);try{if(document.querySelector("body.victory")){var i=[];for(const s of window.nopecha){var c=Net.fetch("https://api.nopecha.com/upload",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});i.push(c)}await Promise.all(i),window.nopecha=[],e&&(window.parent.postMessage({nopecha:!0,action:"reload"},"*"),window.location.reload(!0))}"block"===document.querySelector("#timeout_widget")?.style?.display&&(window.parent.postMessage({nopecha:!0,action:"reload"},"*"),window.location.reload(!0));var r=document.querySelectorAll("#game_children_challenge ul > li > a");for(const l in r){var d=r[l];l in a&&d.removeEventListener("click",a[l]),a[l]=t.bind(this,parseInt(l)),d.addEventListener("click",a[l])}}catch(e){}}})();

Wyświetl plik

@ -0,0 +1 @@
(async()=>{function u(e){e=e?.style.background?.trim()?.match(/(?!^)".*?"/g);return e&&0!==e.length?e[0].replaceAll('"',""):null}async function h(){var e=document.querySelector("h2.prompt-text")?.innerText?.replace(/\s+/g," ")?.trim();if(!e)return null;var t={"0430":"a","0441":"c","0501":"d","0065":"e","0435":"e","04bb":"h","0069":"i","0456":"i","0458":"j","03f3":"j","04cf":"l","03bf":"o","043e":"o","0440":"p","0455":"s","0445":"x","0443":"y","0335":"-"};var a=[];for(const i of e){var c=function(e,t,a){for(;(""+e).length<a;)e=""+t+e;return e}(i.charCodeAt(0).toString(16),"0",4);a.push(c in t?t[c]:i)}return a.join("")}let d=null;async function e(){"block"===document.querySelector("div.check")?.style.display?a=a||!0:(a=!1,await Time.sleep(500),document.querySelector("#checkbox")?.click())}async function t(){"EN"!==document.querySelector(".display-language .text").textContent&&(document.querySelector(".language-selector .option:nth-child(23)").click(),await Time.sleep(500));e=500;var e,{task:t,cells:a,urls:c}=await new Promise(o=>{let r=!1;const s=setInterval(async()=>{if(!r){r=!0;var e=await h();if(e){var t=u(document.querySelector(".challenge-example > .image > .image"));if(t&&""!==t){var a=document.querySelectorAll(".task-image");if(9===a.length){var c=[],i=[];for(const l of a){var n=l.querySelector("div.image");if(!n)return void(r=!1);n=u(n);if(!n||""===n)return void(r=!1);c.push(l),i.push(n)}a=JSON.stringify(i);if(d!==a)return d=a,clearInterval(s),r=!1,o({task:e,task_url:t,cells:c,urls:i})}}}r=!1}},e)}),i=await BG.exec("Settings.get");if(i.enabled&&i.hcaptcha_auto_solve){var n=Time.time(),{data:l,metadata:t}=await NopeCHA.post({captcha_type:IS_DEVELOPMENT?"hcaptcha_dev":"hcaptcha",task:t,image_urls:c,key:i.key});if(l){o&&o.postMessage({event:"NopeCHA.metadata",metadata:t});c=parseInt(i.hcaptcha_solve_delay_time)||3e3,t=i.hcaptcha_solve_delay?c-(Time.time()-n):0;0<t&&await Time.sleep(t);for(let e=0;e<l.length;e++)!1!==l[e]&&"true"!==a[e].getAttribute("aria-pressed")&&a[e].click();await Time.sleep(200);try{document.querySelector(".button-submit").click()}catch(e){}}}}let a=!1,c=!1,o=null;for(;;){await Time.sleep(1e3);var i,n=await BG.exec("Settings.get");n&&n.enabled&&(i=await Location.hostname(),n.disabled_hosts.includes(i)||(c||null!==o||(window.addEventListener("message",e=>{"NopeCHA.hook"===e.data.event&&(o=e.source)}),window.location.hash.includes("frame=challenge")&&(c=!0,"firefox"===await BG.exec("Browser.version")?await Script.inject_file("hcaptcha_hook.js"):await BG.exec("Inject.files",{files:["hcaptcha_hook.js"]}))),n.hcaptcha_auto_open&&0!==document.body.getBoundingClientRect()?.width&&0!==document.body.getBoundingClientRect()?.height&&null!==document.querySelector("div.check")?await e():n.hcaptcha_auto_solve&&null!==document.querySelector("h2.prompt-text")&&await t()))}})();

Wyświetl plik

@ -0,0 +1 @@
(async()=>{let a=null,t=!1,r=!1;function n(e,t,r=!1){e&&(r||a!==e)&&(!0===t&&"false"===e.getAttribute("aria-pressed")||!1===t&&"true"===e.getAttribute("aria-pressed"))&&e.click()}document.addEventListener("mousedown",e=>{"false"===e?.target?.parentNode?.getAttribute("aria-pressed")?(t=!0,r=!0):"true"===e?.target?.parentNode?.getAttribute("aria-pressed")&&(t=!0,r=!1),a=e?.target?.parentNode}),document.addEventListener("mouseup",e=>{t=!1,a=null}),document.addEventListener("mousemove",e=>{t&&(a!==e?.target?.parentNode&&null!==a&&n(a,r,!0),n(e?.target?.parentNode,r))}),window.addEventListener("load",()=>{document.body.appendChild(document.createElement("style")).sheet.insertRule('[aria-pressed="true"] > .border-focus {background-color: #0f0 !important; opacity: 0.3 !important}',0)})})();

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -0,0 +1 @@
(()=>{let e;function t(){var e=navigator.language.split("-")[0];for(const r of document.querySelectorAll('script[src*="hcaptcha.com/1/api.js"]')){var t=new URL(r.src);"en"!==(t.searchParams.get("hl")||e)&&(t.searchParams.set("hl","en"),r.src=t.toString())}}e=new MutationObserver(t),setTimeout(()=>{t(),e.observe(document.head,{childList:!0})},0)})();

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 14 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 11 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 5.8 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 5.2 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 7.6 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 5.9 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 12 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 9.4 KiB

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -0,0 +1,3 @@
{
"update_url": "https://clients2.google.com/service/update2/crx",
"name": "NopeCHA: CAPTCHA Solver", "version": "0.3.3", "description": "Automatically solve reCAPTCHA, hCaptcha, FunCAPTCHA, AWS WAF, and text CAPTCHA using AI.", "permissions": ["declarativeNetRequest", "storage", "scripting", "contextMenus"], "content_scripts": [{"matches": ["<all_urls>"], "js": ["utils.js", "content.js"], "run_at": "document_start", "all_frames": true, "match_about_blank": true}, {"matches": ["*://nopecha.com/setup"], "js": ["setup.js"], "run_at": "document_end", "all_frames": true, "match_about_blank": false}, {"matches": ["*://*.hcaptcha.com/captcha/*"], "js": ["hcaptcha.js"], "run_at": "document_end", "all_frames": true, "match_about_blank": false}, {"matches": ["*://*.hcaptcha.com/captcha/*"], "js": ["hcaptcha_fast.js"], "run_at": "document_start", "all_frames": true, "match_about_blank": false}, {"matches": ["<all_urls>"], "js": ["hcaptcha_language.js"], "run_at": "document_end", "all_frames": true, "match_about_blank": false}, {"matches": ["<all_urls>"], "js": ["recaptcha.js", "recaptcha_speech.js"], "run_at": "document_end", "all_frames": true, "match_about_blank": false}, {"matches": ["*://*.google.com/recaptcha/*", "*://*.recaptcha.net/recaptcha/*", "*://recaptcha.net/recaptcha/*"], "js": ["recaptcha_fast.js"], "run_at": "document_start", "all_frames": true, "match_about_blank": false}, {"matches": ["*://*.arkoselabs.com/fc/*", "*://*.funcaptcha.com/fc/*"], "js": ["funcaptcha.js", "funcaptcha_scrape.js"], "run_at": "document_end", "all_frames": true, "match_about_blank": true}, {"matches": ["*://*.arkoselabs.com/fc/*", "*://*.funcaptcha.com/fc/*"], "js": ["funcaptcha_fast.js"], "run_at": "document_start", "all_frames": true, "match_about_blank": true}, {"matches": ["*://nopecha.com/demo/funcaptcha"], "js": ["funcaptcha_demo.js"], "run_at": "document_end", "all_frames": false, "match_about_blank": false}, {"matches": ["<all_urls>"], "js": ["awscaptcha.js"], "run_at": "document_end", "all_frames": true, "match_about_blank": false}, {"matches": ["<all_urls>"], "js": ["textcaptcha.js", "locate.js"], "run_at": "document_end", "all_frames": true, "match_about_blank": true}], "icons": {"16": "icon/16.png", "32": "icon/32.png", "48": "icon/48.png", "128": "icon/128.png"}, "manifest_version": 3, "action": {"default_title": "NopeCHA: CAPTCHA Solver", "default_icon": "icon/16.png", "default_popup": "popup.html"}, "background": {"service_worker": "background.js", "type": "module"}, "host_permissions": ["<all_urls>"]}

Wyświetl plik

@ -0,0 +1,801 @@
@font-face {
font-family: 'plex-sans';
font-style: normal;
font-weight: 700;
src: url('font/plex-sans-bold.woff2') format('woff2'), url('font/plex-sans-bold.woff') format('woff');
}
@font-face {
font-family: 'plex-sans';
font-style: normal;
font-weight: 400;
src: url('font/plex-sans-regular.woff2') format('woff2'), url('font/plex-sans-regular.woff') format('woff');
}
* {
font-family: 'plex-sans';
box-sizing: border-box;
outline: none;
}
html {
width: 340px;
}
body {
width: 324px;
}
html, body {
background: #1a2432;
color: #fff;
line-height: 1.15;
text-size-adjust: 100%;
}
div {
display: block;
}
a {
text-decoration: none;
}
button, input, optgroup, select, textarea {
font-family: inherit;
font-size: 100%;
line-height: 1.15;
margin: 0px;
}
button, select {
text-transform: none;
}
button, input {
overflow: visible;
}
input {
writing-mode: horizontal-tb !important;
font-style: ;
font-variant-ligatures: ;
font-variant-caps: ;
font-variant-numeric: ;
font-variant-east-asian: ;
font-weight: ;
font-stretch: ;
font-size: ;
font-family: ;
text-rendering: auto;
color: fieldtext;
letter-spacing: normal;
word-spacing: normal;
line-height: normal;
text-transform: none;
text-indent: 0px;
text-shadow: none;
display: inline-block;
text-align: start;
appearance: auto;
-webkit-rtl-ordering: logical;
cursor: text;
background-color: field;
margin: 0em;
padding: 1px 2px;
border-width: 2px;
border-style: inset;
border-color: -internal-light-dark(rgb(118, 118, 118), rgb(133, 133, 133));
border-image: initial;
}
.text_input {
background-color: transparent;
padding: 8px 8px 8px 16px;
color: rgb(255, 255, 255);
outline: none;
border: none;
width: 100%;
font-size: 14px;
}
.text_input.small {
width: 30%;
}
.text_input.text_right {
text-align: right;
}
.hidden {
display: none !important;
}
.hiddenleft {
transform: translateX(-100%) translateZ(0px);
}
.red {
color: #ff6961 !important;
}
/* Remove arrows from number input */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type=number] {
-moz-appearance: textfield;
}
/* SCROLLBAR */
::-webkit-scrollbar {
width: 6px;
right: 2px;
bottom: 2px;
top: 2px;
border-radius: 3px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.2);
}
/* LOADING OVERLAY */
#loading_overlay {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: #222;
z-index: 10;
}
#loading_overlay .loading_text {
margin-top: 8px;
font-size: 14px;
text-align: center;
}
#loading_overlay .loading_text.timeout > div {
opacity: 0;
animation: fadein 10s linear forwards;
}
#loading_overlay .loading_text.timeout > div:nth-child(1) {
animation-delay: 2000ms;
}
#loading_overlay .loading_text.timeout > div:nth-child(2) {
animation-delay: 4000ms;
}
#loading_overlay .loading_text.timeout > div:nth-child(3) {
animation-delay: 6000ms;
}
@keyframes fadein {
0% {opacity: 0;}
50% {opacity: 0;}
100% {opacity: 1;}
}
/* MISC */
.clickable {
cursor: pointer !important;
}
.clickable:hover {
opacity: 0.8 !important;
}
/* APP */
#app_frame {
display: flex;
flex-direction: column;
overflow: hidden;
transition: height ease 0.2s, min-height ease 0.2s;
min-height: 237px !important;
}
/* HEADER */
.header {
box-sizing: border-box;
padding: 16px;
display: flex;
place-content: space-between;
font-weight: 400;
}
.header.spacedright {
margin-right: 32px;
}
.nav_icon {
border: none;
cursor: pointer;
display: flex;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: center;
justify-content: center;
background: rgba(2, 13, 28, 0.05);
border-radius: 50%;
width: 32px;
height: 32px;
position: relative;
transition: all 0.3s ease 0s;
fill: rgba(255, 255, 255, 1);
background: rgba(255, 255, 255, 0.1) !important;
}
.nav_icon:hover {
opacity: 0.9;
}
.nav_icon:disabled,
.nav_icon:disabled:hover {
background: none !important;
cursor: unset;
opacity: 0.9;
}
.header_label_container {
box-sizing: border-box;
margin-right: 0px;
display: flex;
flex: 1 1 0%;
-webkit-box-pack: center;
justify-content: center;
-webkit-box-align: center;
align-items: center;
}
.header_label {
box-sizing: border-box;
font-size: 24px;
font-weight: bold;
display: flex;
color: rgb(255, 255, 255);
}
/* PLAN */
.plan_info_box {
position: relative;
width: 100%;
height: 100%;
}
.plan_info_container {
display: flex;
box-sizing: border-box;
position: relative;
}
.plan_info {
box-sizing: border-box;
width: 100%;
padding: 0px 16px 16px;
display: flex;
}
.plan_label {
box-sizing: border-box;
font-weight: bold;
font-size: 14px;
color: rgb(255, 255, 255);
}
.plan_value {
box-sizing: border-box;
margin-left: auto;
display: flex;
}
.plan_button {
display: flex;
background-color: transparent;
color: rgba(255, 255, 255, 0.9);
width: auto;
padding: 0px;
border: none;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: center;
justify-content: center;
transition: color 0.3s ease 0s, transform 0.1s ease-out 0s, opacity 0.3s ease 0s;
}
.plan_button.link {
color: #0a95ff;
}
.plan_button.link,
.plan_button.link:hover,
.plan_button_label {
box-sizing: border-box;
font-size: 14px;
}
/* WARNING */
.warning_box {
display: flex;
flex-direction: column;
justify-content: center;
background: #1a2432;
position: absolute;
top: 0;
bottom: 8px;
left: 4px;
right: 4px;
border: 1px solid #FCD62E;
border-radius: 0.25rem;
padding: 0.5rem;
margin: 0 4px;
z-index: 1;
}
.warning_box * {
color: #fff;
font-size: 14px;
text-align: center;
}
/* KEY */
.key_label {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
width: 100%;
}
.key_label > .instructions {
font-weight: normal;
line-height: 16px;
margin-left: 6px;
color: #fff;
font-size: 10px;
}
.settings_text[data-settings="key"] {
background: #1a2432;
position: absolute;
width: calc(100% - 32px);
transition: all ease 0.1s;
z-index: 1;
}
/* .edit_key {
line-height: 16px;
margin-right: 6px;
color: #fff;
font-size: 10px;
} */
.edit_icon {
z-index: 2;
}
/* MENU */
.menu {
box-sizing: border-box;
padding-left: 16px;
}
.menu_item_container {
border-top: none;
border-right: none;
border-left: none;
border-image: initial;
cursor: pointer;
display: flex;
-webkit-box-align: center;
align-items: center;
background-color: transparent;
width: 100%;
padding: 16px;
margin-top: 2px;
border-bottom: 2px solid rgba(255, 255, 255, 0.05);
color: rgba(255, 255, 255, 0.5);
transition: color 0.5s ease 0s, border 0.5s ease 0s;
-webkit-box-pack: justify !important;
justify-content: space-between !important;
}
.menu_item_container:hover {
color: rgb(255, 255, 255);
}
button.menu_item_container {
padding-left: 0px !important;
}
.button_label_container {
box-sizing: border-box;
-webkit-box-align: center;
align-items: center;
display: flex;
}
.button_label_container svg {
fill: rgb(255, 255, 255);
}
.button_label {
box-sizing: border-box;
margin-left: 16px;
font-size: 14px;
font-weight: bold;
}
.menu_item_arrow {
fill: rgb(255, 255, 255);
height: 16px;
width: 16px;
}
/* #export {
color: rgba(255, 255, 255, 0.5);
font-size: 1.2em;
cursor: pointer;
transition: color 0.5s ease 0s, border 0.5s ease 0s;
}
#export:hover {
color: rgb(255, 255, 255);
} */
/* TAB */
.bbflex {
box-sizing: border-box;
display: flex;
-webkit-box-align: center;
align-items: center;
}
.scrolling_container {
box-sizing: border-box;
margin-top: 8px;
margin-left: 16px;
margin-right: 16px;
padding-bottom: 16px;
}
.settings_item_container {
box-sizing: border-box;
margin-bottom: 8px;
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 8px;
box-sizing: border-box;
}
.settings_item_container > a {
color: rgba(255, 255, 255, 0.5);
text-decoration: none;
transition: color 0.5s ease 0s, border 0.5s ease 0s;
}
.settings_item {
width: 100%;
background-color: rgba(255, 255, 255, 0.08);
min-height: 48px;
padding: 14px 16px 0px;
border-radius: 8px;
}
.settings_item > div {
-webkit-box-pack: justify;
justify-content: space-between;
-webkit-box-align: center;
align-items: center;
}
.settings_item_label {
font-size: 14px;
font-weight: 600;
color: rgb(255, 255, 255);
padding-left: 16px;
height: 20px;
-webkit-box-align: center;
align-items: center;
}
.settings_toggle {
height: 20px;
max-width: 36px;
min-width: 36px;
border-radius: 10px;
padding: 2px;
transition: background-color 0.3s ease 0s;
opacity: 1;
cursor: pointer;
}
.settings_toggle > div {
width: 16px;
height: 16px;
border-radius: 50%;
transform: translate(16px);
transition: transform 0.3s ease 0s, background-color 0.3s ease 0s;
}
.settings_toggle.on {
background-color: rgb(0, 106, 255);
}
.settings_toggle.off {
background-color: rgb(255, 255, 255);
}
.settings_toggle.on > div {
background-color: rgb(255, 255, 255);
transform: translate(16px);
}
.settings_toggle.off > div {
background-color: rgb(2, 13, 28);
transform: translate(0px);
}
.settings_description_container {
padding: 10px 16px 8px;
-webkit-box-pack: justify;
justify-content: space-between;
}
.settings_description {
font-size: 12px;
color: rgba(255, 255, 255, 0.5);
}
.settings_button {
color: rgba(255, 255, 255, 0.5);
font-size: 14px;
gap: 16px;
}
.settings_button > div {
cursor: pointer;
transition: all 0.3s ease 0s;
}
.settings_button > div:hover {
color: rgb(255, 255, 255);
}
.settings_dropdown_selected {
color: rgba(255, 255, 255, 0.5);
-webkit-box-align: center;
align-items: center;
font-size: 14px;
cursor: pointer;
white-space: nowrap;
}
.settings_dropdown_selected > div {
box-sizing: border-box;
margin-right: 8px;
}
.settings_dropdown_options {
position: relative;
transition: visibility 0.3s ease 0s, opacity 0.3s ease 0s;
opacity: 0;
visibility: hidden;
}
.settings_dropdown_options > div {
position: absolute;
background-color: rgb(255, 255, 255);
border-radius: 4px;
right: 0px;
top: 50%;
transform: translateY(-50%);
border: 1px solid rgba(0, 0, 0, 0.15);
width: auto;
min-width: 60px;
white-space: nowrap;
box-shadow: rgb(0 0 0 / 15%) 0px 2px 4px 0px;
box-sizing: border-box;
padding: 4px;
}
.settings_dropdown_selected:hover > .settings_dropdown_options {
opacity: 1;
visibility: visible;
}
.settings_dropdown_options > div > div {
color: rgba(0, 0, 0, 0.5);
font-weight: 700;
border-radius: 4px;
-webkit-box-pack: center;
justify-content: center;
-webkit-box-align: center;
align-items: center;
line-height: normal;
font-size: 12px;
height: 23px;
cursor: pointer;
padding: 0px 4px;
}
.settings_dropdown_options > div > div:hover {
background-color: rgba(0, 0, 0, 0.08);
}
.settings_dropdown_options > div > div.selected {
color: rgb(0, 106, 255);
}
/* FOOTER */
.footer {
display: flex;
flex-direction: row;
padding: 8px;
margin-top: 8px;
font-size: 10px;
}
.footer * {
color: rgba(255, 255, 255, 0.8);
}
.footer > *:nth-child(1) {
flex-grow: 1;
}
/* LOADING ANIM */
.loading {
display: inline-block;
position: relative;
width: 32px;
height: 16px;
}
.loading div {
position: absolute;
top: 5px;
width: 6px;
height: 6px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.8);
animation-timing-function: cubic-bezier(0, 1, 1, 0);
}
.loading div:nth-child(1) {
left: 4px;
animation: loading1 0.6s infinite;
}
.loading div:nth-child(2) {
left: 4px;
animation: loading2 0.6s infinite;
}
.loading div:nth-child(3) {
left: 16px;
animation: loading2 0.6s infinite;
}
.loading div:nth-child(4) {
left: 28px;
animation: loading3 0.6s infinite;
}
@keyframes loading1 {
0% {
transform: scale(0);
}
100% {
transform: scale(1);
}
}
@keyframes loading3 {
0% {
transform: scale(1);
}
100% {
transform: scale(0);
}
}
@keyframes loading2 {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(12px, 0);
}
}
/* POWER ANIM */
#power .btn {
width: 32px;
height: 32px;
transition: transform 0.3s ease 0s;
}
#power .btn.off {
transform: rotate(-180deg);
}
#power .btn_outline {
position: absolute;
z-index: 2;
height: 100%;
}
#power .btn_outline.spinning {
animation: 1s linear 0s infinite normal none running spinning;
}
@keyframes spinning {
0% {transform: rotate(0deg);}
100% {transform: rotate(360deg);}
}
/* GLOW ANIM */
.hover_glow {
border: none;
outline: none;
cursor: pointer;
position: relative;
z-index: 0;
border-radius: 50%;
}
.hover_glow:before {
content: '';
background: linear-gradient(45deg, #ff0000, #ff7300, #fffb00, #48ff00, #00ffd5, #002bff, #7a00ff, #ff00c8, #ff0000);
position: absolute;
top: -2px;
left:-2px;
background-size: 400%;
z-index: -1;
filter: blur(5px);
width: calc(100% + 4px);
height: calc(100% + 4px);
animation: glowing 20s linear infinite;
opacity: 0;
transition: opacity .3s ease-in-out;
border-radius: 50%;
}
.hover_glow:active:after {
background: transparent;
}
.hover_glow:hover:before {
opacity: 1;
}
.hover_glow:after {
z-index: -1;
content: '';
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
border-radius: 50%;
}
.hover_glow.static:before {
opacity: 1 !important;
}
@keyframes glowing {
0% {background-position: 0 0;}
50% {background-position: 400% 0;}
100% {background-position: 0 0;}
}
/* BLACKLIST */
.settings_item_header {
box-sizing: border-box;
padding-top: 4px;
padding-bottom: 8px;
font-size: 12px;
background-color: rgb(26, 36, 50);
width: 100%;
letter-spacing: 2px;
font-weight: bold;
color: rgba(255, 255, 255, 0.5);
text-transform: uppercase;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
position: relative;
top: 12px;
z-index: 1;
}
.settings_item_container.list_item {
border-radius: 0;
border: none;
border-bottom: 2px solid rgba(255, 255, 255, 0.05);
padding-top: 16px;
padding-bottom: 16px;
margin-bottom: 0px;
}
.list_item_row {
box-sizing: border-box;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: justify;
justify-content: space-between;
width: 100%;
display: flex;
}
#current_page_host {
box-sizing: border-box;
font-size: 14px;
font-weight: bold;
color: rgb(255, 255, 255);
width: fit-content;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 220px;
}
.settings_text.text_input.list_input {
flex-grow: 1;
padding-left: 0;
}
.list_item_button {
border: none;
cursor: pointer;
display: flex;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: center;
justify-content: center;
background-color: transparent;
padding: 0px;
transition: background-color 0.3s ease 0s, color 0.3s ease 0s, transform 0.1s ease-out 0s, opacity 0.3s ease 0s;
opacity: 0.5;
height: 32px;
width: 32px;
margin-right: -4px;
}
.list_item_button:hover {
opacity: 1.0;
}
.list_item_button:disabled,
.list_item_button:disabled:hover {
opacity: 0.3;
cursor: unset;
}

Wyświetl plik

@ -0,0 +1,873 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<div id="loading_overlay">
<a href="https://nopecha.com/discord" target="_blank"></a>
<button class="nav_icon hover_glow static">
<img src="/icon/32.png" alt="NopeCHA">
</button>
</a>
<div class='loading_text'>Loading</div>
<div class='loading_text timeout'>
<div>This is taking longer than usual.</div>
<div>Please close this window and try again.</div>
<div>If the problem persists, contact us on <a style="color: #fff;" href="https://nopecha.com/discord" target="_blank">Discord</a></div>
</div>
</div>
<div id="template" class="hidden">
<div id="disabled_hosts_item" class="settings_item_container list_item">
<div class="list_item_row">
<input type="text" autocomplete="off" spellcheck="false" placeholder="Enter hostname" value="" class="settings_text text_input list_input hostname">
<button class="list_item_button remove">
<svg width="16" height="16" fill="#ffffff">
<path d="M9 2H7v12h2V2zm2.75 0l-1.5 12h1.98l1.5-12h-1.98zm-7.5 0H2.27l1.5 12h1.98L4.25 2zM0 0h16l-2 16H2L0 0z"></path>
</svg>
</button>
</div>
</div>
</div>
<div id="app_frame">
<!-- HCAPTCHA TAB -->
<div class="tab hidden" data-tab="hcaptcha">
<div class="header">
<button class="nav_icon back" data-tabtarget="main">
<svg width="12" height="12" viewBox="0 0 9 16"><path d="M2.684 8l6.038-6.308c.37-.387.37-1.015 0-1.402a.92.92 0 00-1.342 0L0 8l7.38 7.71a.92.92 0 001.342 0c.37-.387.37-1.015 0-1.402L2.684 8z"></path></svg>
</button>
<div class="header_label_container">
<div class="header_label">hCaptcha</div>
</div>
<a href="https://nopecha.com/demo/hcaptcha" target="_blank">
<button class="nav_icon">
<svg width="16" height="16" viewBox="20 20 560 560"><path d="m374.48 524.29h74.9v74.89h-74.9z" fill="#0074bf" opacity=".502"/><path d="m299.59 524.29h74.89v74.89h-74.89zm-74.89 0h74.89v74.89h-74.89z" fill="#0074bf" opacity=".702"/><path d="m149.8 524.29h74.9v74.89h-74.9z" fill="#0074bf" opacity=".502"/><g fill="#0082bf"><path d="m449.39 449.39h74.9v74.9h-74.9z" opacity=".702"/><path d="m374.48 449.39h74.9v74.9h-74.9z" opacity=".8"/><path d="m299.59 449.39h74.89v74.9h-74.89zm-74.89 0h74.89v74.9h-74.89z"/><path d="m149.8 449.39h74.9v74.9h-74.9z" opacity=".8"/><path d="m74.89 449.39h74.9v74.9h-74.9z" opacity=".702"/></g><g fill="#008fbf"><path d="m524.29 374.48h74.89v74.9h-74.89z" opacity=".502"/><path d="m449.39 374.48h74.9v74.9h-74.9z" opacity=".8"/><path d="m374.48 374.48h74.9v74.9h-74.9zm-74.89 0h74.89v74.9h-74.89zm-74.89 0h74.89v74.9h-74.89z"/><path d="m149.8 374.48h74.9v74.9h-74.9z"/><path d="m74.89 374.48h74.9v74.9h-74.9z" opacity=".8"/><path d="m0 374.48h74.89v74.9h-74.89z" opacity=".502"/></g><path d="m524.29 299.59h74.89v74.89h-74.89z" fill="#009dbf" opacity=".702"/><path d="m449.39 299.59h74.9v74.89h-74.9zm-74.91 0h74.9v74.89h-74.9zm-74.89 0h74.89v74.89h-74.89zm-74.89 0h74.89v74.89h-74.89z" fill="#009dbf"/><path d="m149.8 299.59h74.9v74.89h-74.9zm-74.91 0h74.9v74.89h-74.9z" fill="#009dbf"/><path d="m0 299.59h74.89v74.89h-74.89z" fill="#009dbf" opacity=".702"/><path d="m524.29 224.7h74.89v74.89h-74.89z" fill="#00abbf" opacity=".702"/><path d="m449.39 224.7h74.9v74.89h-74.9zm-74.91 0h74.9v74.89h-74.9zm-74.89 0h74.89v74.89h-74.89zm-74.89 0h74.89v74.89h-74.89z" fill="#00abbf"/><path d="m149.8 224.7h74.9v74.89h-74.9zm-74.91 0h74.9v74.89h-74.9z" fill="#00abbf"/><path d="m0 224.7h74.89v74.89h-74.89z" fill="#00abbf" opacity=".702"/><g fill="#00b9bf"><path d="m524.29 149.8h74.89v74.9h-74.89z" opacity=".502"/><path d="m449.39 149.8h74.9v74.9h-74.9z" opacity=".8"/><path d="m374.48 149.8h74.9v74.9h-74.9zm-74.89 0h74.89v74.9h-74.89zm-74.89 0h74.89v74.9h-74.89z"/><path d="m149.8 149.8h74.9v74.9h-74.9z"/><path d="m74.89 149.8h74.9v74.9h-74.9z" opacity=".8"/><path d="m0 149.8h74.89v74.9h-74.89z" opacity=".502"/></g><g fill="#00c6bf"><path d="m449.39 74.89h74.9v74.9h-74.9z" opacity=".702"/><path d="m374.48 74.89h74.9v74.9h-74.9z" opacity=".8"/><path d="m299.59 74.89h74.89v74.9h-74.89zm-74.89 0h74.89v74.9h-74.89z"/><path d="m149.8 74.89h74.9v74.9h-74.9z" opacity=".8"/><path d="m74.89 74.89h74.9v74.9h-74.9z" opacity=".702"/></g><path d="m374.48 0h74.9v74.89h-74.9z" fill="#00d4bf" opacity=".502"/><path d="m299.59 0h74.89v74.89h-74.89zm-74.89 0h74.89v74.89h-74.89z" fill="#00d4bf" opacity=".702"/><path d="m149.8 0h74.9v74.89h-74.9z" fill="#00d4bf" opacity=".502"/><path d="m197.2 275.96 20.87-46.71c7.61-11.97 6.6-26.64-1.72-34.96-.28-.28-.56-.55-.86-.81-.29-.26-.59-.52-.89-.76a21.043 21.043 0 0 0 -1.92-1.37 22.68 22.68 0 0 0 -4.51-2.13c-1.58-.55-3.21-.92-4.87-1.12-1.66-.19-3.34-.2-5-.03s-3.3.51-4.88 1.04c-1.79.55-3.53 1.27-5.19 2.13a32.32 32.32 0 0 0 -4.72 3.02 32.38 32.38 0 0 0 -4.12 3.82 32 32 0 0 0 -3.37 4.48c-.98 1.59-28.57 66.66-39.2 96.62s-6.39 84.91 34.61 125.99c43.48 43.48 106.43 53.41 146.58 23.28.42-.21.84-.44 1.24-.67.41-.23.81-.48 1.2-.74.4-.25.78-.52 1.16-.8.38-.27.75-.56 1.11-.86l123.73-103.32c6.01-4.97 14.9-15.2 6.92-26.88-7.79-11.39-22.55-3.64-28.57.21l-71.21 51.78c-.33.27-.72.48-1.13.6-.42.12-.85.16-1.28.11s-.85-.19-1.22-.4c-.38-.21-.71-.5-.97-.85-1.81-2.22-2.13-8.11.71-10.44l109.16-92.64c9.43-8.49 10.74-20.84 3.1-29.3-7.45-8.29-19.29-8.04-28.8.53l-98.28 76.83c-.46.38-.99.66-1.56.82s-1.17.21-1.76.13-1.15-.27-1.66-.58c-.51-.3-.96-.7-1.3-1.18-1.94-2.18-2.69-5.89-.5-8.07l111.3-108.01c2.09-1.95 3.78-4.29 4.96-6.88 1.18-2.6 1.85-5.41 1.95-8.26s-.36-5.7-1.36-8.37c-1-2.68-2.51-5.13-4.45-7.22-.97-1.03-2.05-1.95-3.2-2.75a21.14 21.14 0 0 0 -3.69-2.05c-1.3-.55-2.65-.97-4.03-1.26-1.38-.28-2.79-.42-4.2-.41-1.44-.02-2.88.1-4.29.37a21.906 21.906 0 0 0 -7.96 3.16c-1.21.78-2.34 1.68-3.38 2.68l-113.73 106.83c-2.72 2.72-8.04 0-8.69-3.18-.06-.28-.08-.57-.07-.86s.06-.58.15-.85c.08-.28.2-.55.35-.79.15-.25.33-.48.54-.68l87.05-99.12a21.38 21.38 0 0 0 6.82-15.3c.11-5.81-2.15-11.42-6.25-15.53-4.11-4.12-9.71-6.4-15.52-6.31s-11.34 2.53-15.32 6.77l-132.01 145.95c-4.73 4.73-11.7 4.97-15.02 2.22-.51-.4-.93-.9-1.24-1.46-.32-.56-.52-1.18-.6-1.82-.08-.65-.03-1.3.14-1.92s.46-1.21.85-1.72z" fill="#fff"/></svg>
</button>
</a>
</div>
<div style="position: relative; overflow: hidden; width: 100%; height: auto; min-height: 0px; max-height: 402px;">
<div style="position: relative; overflow: auto; margin-bottom: -15px; min-height: 15px; max-height: 417px;">
<div class="scrolling_container">
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M8 0A8 8 0 11.582 11.001h2.221a6 6 0 100-6L.582 4.999A8.003 8.003 0 018 0zM7 5l4 3-4 3-.001-2H0V7h6.999L7 5z"></path></svg>
<div class="settings_item_label bbflex">Auto-Open</div>
</div>
<div class="bbflex">
<div class="settings_toggle off" data-settings="hcaptcha_auto_open">
<div></div>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Automatically opens captcha challenges.</div>
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M13.336 9.007l.044.085 2.58 6.193a.516.516 0 01-.91.48l-.043-.083-.728-1.747h-2.753l-.727 1.747a.516.516 0 01-.586.306l-.089-.028a.516.516 0 01-.306-.586l.028-.089 2.58-6.193a.517.517 0 01.91-.085zM4.128 1.728V4.13a5.161 5.161 0 004.13 9.187v2.095A7.226 7.226 0 014.128 1.73zm8.775 8.904l-.947 2.271h1.893l-.946-2.27zM8.258 0v8.258H6.193V0h2.065zm2.065 1.728a7.233 7.233 0 014.055 5.498h-2.094a5.162 5.162 0 00-1.962-3.097V1.728z"></path></svg>
<div class="settings_item_label bbflex">Auto-Solve</div>
</div>
<div class="bbflex">
<div class="settings_toggle off" data-settings="hcaptcha_auto_solve">
<div></div>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Automatically solves captcha challenges.</div>
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M12.214 10l.964 3H14.5a1.5 1.5 0 010 3h-13a1.5 1.5 0 010-3h1.322l.964-3h8.428zm-1.607-5l.964 3H4.429l.964-3h5.214zM9 0l.964 3H6.036L7 0h2z"></path></svg>
<div class="settings_item_label bbflex">Delay solving</div>
</div>
<div class="bbflex">
<div class="settings_toggle off" data-settings="hcaptcha_solve_delay">
<div></div>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Adds a delay to avoid detection.</div>
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M16 8a8 8 0 01-8 8v-1a7 7 0 007-7h1zm-4.667 3.536l.667.707C10.976 13.33 9.562 14 8 14c-1.562 0-2.976-.671-4-1.757l.667-.707C5.52 12.441 6.698 13 8 13s2.48-.56 3.333-1.464zM7 4.5a.5.5 0 01.492.41L7.5 5v3.5H10a.5.5 0 01.492.41L10.5 9a.5.5 0 01-.41.492L10 9.5H6.5V5a.5.5 0 01.5-.5zM8 0v1a7 7 0 00-7 7H0a8 8 0 018-8zm0 2c1.562 0 2.977.672 4 1.758l-.666.707C10.48 3.56 9.302 3 8 3s-2.48.56-3.334 1.465L4 3.758C5.023 2.672 6.438 2 8 2z"></path></svg>
<div class="settings_item_label bbflex">Delay Timer</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Milliseconds to delay solving.</div>
<input type="number" autocomplete="off" spellcheck="false" placeholder="Delay" value="" class="settings_text text_input text_right small" data-settings="hcaptcha_solve_delay_time">
</div>
</div>
</div>
</div>
</div>
</div>
<!-- RECAPTCHA TAB -->
<div class="tab hidden" data-tab="recaptcha">
<div class="header">
<button class="nav_icon back" data-tabtarget="main">
<svg width="12" height="12" viewBox="0 0 9 16"><path d="M2.684 8l6.038-6.308c.37-.387.37-1.015 0-1.402a.92.92 0 00-1.342 0L0 8l7.38 7.71a.92.92 0 001.342 0c.37-.387.37-1.015 0-1.402L2.684 8z"></path></svg>
</button>
<div class="header_label_container">
<div class="header_label">reCAPTCHA</div>
</div>
<a href="https://nopecha.com/demo/recaptcha" target="_blank">
<button class="nav_icon">
<svg width="16" height="16" viewBox="0 0 64 64"><path d="M64 31.955l-.033-1.37V4.687l-7.16 7.16C50.948 4.674 42.033.093 32.05.093c-10.4 0-19.622 4.96-25.458 12.64l11.736 11.86a15.55 15.55 0 0 1 4.754-5.334c2.05-1.6 4.952-2.906 8.968-2.906.485 0 .86.057 1.135.163 4.976.393 9.288 3.14 11.828 7.124l-8.307 8.307L64 31.953" fill="#1c3aa9"/><path d="M31.862.094l-1.37.033H4.594l7.16 7.16C4.58 13.147 0 22.06 0 32.046c0 10.4 4.96 19.622 12.64 25.458L24.5 45.768a15.55 15.55 0 0 1-5.334-4.754c-1.6-2.05-2.906-4.952-2.906-8.968 0-.485.057-.86.163-1.135.393-4.976 3.14-9.288 7.124-11.828l8.307 8.307L31.86.095" fill="#4285f4"/><path d="M.001 32.045l.033 1.37v25.898l7.16-7.16c5.86 7.173 14.774 11.754 24.76 11.754 10.4 0 19.622-4.96 25.458-12.64l-11.736-11.86a15.55 15.55 0 0 1-4.754 5.334c-2.05 1.6-4.952 2.906-8.968 2.906-.485 0-.86-.057-1.135-.163-4.976-.393-9.288-3.14-11.828-7.124l8.307-8.307c-10.522.04-22.4.066-27.295-.005" fill="#ababab"/></svg>
</button>
</a>
</div>
<div style="position: relative; overflow: hidden; width: 100%; height: auto; min-height: 0px; max-height: 402px;">
<div style="position: relative; overflow: auto; margin-bottom: -15px; min-height: 15px; max-height: 417px;">
<div class="scrolling_container">
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M8 0A8 8 0 11.582 11.001h2.221a6 6 0 100-6L.582 4.999A8.003 8.003 0 018 0zM7 5l4 3-4 3-.001-2H0V7h6.999L7 5z"></path></svg>
<div class="settings_item_label bbflex">Auto-Open</div>
</div>
<div class="bbflex">
<div class="settings_toggle off" data-settings="recaptcha_auto_open">
<div></div>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Automatically opens captcha challenges.</div>
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M13.336 9.007l.044.085 2.58 6.193a.516.516 0 01-.91.48l-.043-.083-.728-1.747h-2.753l-.727 1.747a.516.516 0 01-.586.306l-.089-.028a.516.516 0 01-.306-.586l.028-.089 2.58-6.193a.517.517 0 01.91-.085zM4.128 1.728V4.13a5.161 5.161 0 004.13 9.187v2.095A7.226 7.226 0 014.128 1.73zm8.775 8.904l-.947 2.271h1.893l-.946-2.27zM8.258 0v8.258H6.193V0h2.065zm2.065 1.728a7.233 7.233 0 014.055 5.498h-2.094a5.162 5.162 0 00-1.962-3.097V1.728z"></path></svg>
<div class="settings_item_label bbflex">Auto-Solve</div>
</div>
<div class="bbflex">
<div class="settings_toggle off" data-settings="recaptcha_auto_solve">
<div></div>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Automatically solves captcha challenges.</div>
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M12.214 10l.964 3H14.5a1.5 1.5 0 010 3h-13a1.5 1.5 0 010-3h1.322l.964-3h8.428zm-1.607-5l.964 3H4.429l.964-3h5.214zM9 0l.964 3H6.036L7 0h2z"></path></svg>
<div class="settings_item_label bbflex">Delay solving</div>
</div>
<div class="bbflex">
<div class="settings_toggle off" data-settings="recaptcha_solve_delay">
<div></div>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Adds a delay to avoid detection.</div>
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M16 8a8 8 0 01-8 8v-1a7 7 0 007-7h1zm-4.667 3.536l.667.707C10.976 13.33 9.562 14 8 14c-1.562 0-2.976-.671-4-1.757l.667-.707C5.52 12.441 6.698 13 8 13s2.48-.56 3.333-1.464zM7 4.5a.5.5 0 01.492.41L7.5 5v3.5H10a.5.5 0 01.492.41L10.5 9a.5.5 0 01-.41.492L10 9.5H6.5V5a.5.5 0 01.5-.5zM8 0v1a7 7 0 00-7 7H0a8 8 0 018-8zm0 2c1.562 0 2.977.672 4 1.758l-.666.707C10.48 3.56 9.302 3 8 3s-2.48.56-3.334 1.465L4 3.758C5.023 2.672 6.438 2 8 2z"></path></svg>
<div class="settings_item_label bbflex">Delay Timer</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Milliseconds to delay solving.</div>
<input type="number" autocomplete="off" spellcheck="false" placeholder="Delay" value="" class="settings_text text_input text_right small" data-settings="recaptcha_solve_delay_time">
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M10.833 0C12.03 0 13 .895 13 2v2h-2V2H2v12h2v2H2.167C.97 16 0 15.105 0 14V2C0 .895.97 0 2.167 0h8.666zM9.5 5a4.5 4.5 0 013.81 6.895l2.397 2.398a1 1 0 01-1.32 1.497l-.094-.083-2.398-2.396A4.5 4.5 0 119.5 5zm0 2a2.5 2.5 0 100 5 2.5 2.5 0 000-5z"></path></svg>
<div class="settings_item_label bbflex">Solve Method</div>
</div>
<div class="bbflex">
<div class="settings_dropdown_selected bbflex">
<div id="recaptcha_solve_method">Image</div>
<div class="settings_dropdown_options" style="box-sizing: border-box;">
<div>
<div data-displays="#recaptcha_solve_method" data-value="Image" class="settings_dropdown bbflex" data-settings="recaptcha_solve_method">Image</div>
<div data-displays="#recaptcha_solve_method" data-value="Speech" class="settings_dropdown bbflex" data-settings="recaptcha_solve_method">Speech</div>
</div>
</div>
<svg width="16" height="16" fill="rgba(255, 255, 255, 0.5)"><path d="M5.302 9.225L8 11.878l2.7-2.653a.77.77 0 011.079 0 .744.744 0 010 1.06L8 14l-3.778-3.714a.744.744 0 010-1.061.77.77 0 011.08 0zM7.999 2l3.783 3.715.009.009a.744.744 0 01-.01 1.051.77.77 0 01-1.078 0L8.004 4.122 5.306 6.775a.77.77 0 01-1.088-.008.745.745 0 01.008-1.053L7.999 2z" fill-rule="evenodd"></path></svg>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Method used to solve the captcha.</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- FUNCAPTCHA TAB -->
<div class="tab hidden" data-tab="funcaptcha">
<div class="header">
<button class="nav_icon back" data-tabtarget="main">
<svg width="12" height="12" viewBox="0 0 9 16"><path d="M2.684 8l6.038-6.308c.37-.387.37-1.015 0-1.402a.92.92 0 00-1.342 0L0 8l7.38 7.71a.92.92 0 001.342 0c.37-.387.37-1.015 0-1.402L2.684 8z"></path></svg>
</button>
<div class="header_label_container">
<div class="header_label">FunCAPTCHA</div>
</div>
<a href="https://nopecha.com/demo/funcaptcha" target="_blank">
<button class="nav_icon">
<svg width="16" height="16" viewBox="18 30 37 34"><path d="M52.107,37.991,38.249,30a3.992,3.992,0,0,0-1.919-.533A3.606,3.606,0,0,0,34.412,30L20.555,37.991a3.829,3.829,0,0,0-1.919,3.3V57.338a3.9,3.9,0,0,0,1.919,3.3l.959.533,4.423,2.558V56.326l10.393-5.969,10.393,5.969v7.355l4.423-2.558.959-.586a3.829,3.829,0,0,0,1.919-3.3V41.243A3.857,3.857,0,0,0,52.107,37.991ZM46.617,47.9,38.2,43a3.99,3.99,0,0,0-1.918-.533A3.607,3.607,0,0,0,34.359,43l-8.474,4.9V43.268l8.688-5.01a3.425,3.425,0,0,1,3.358,0l8.688,5.01Z" fill="#50b95d"/></svg>
</button>
</a>
</div>
<div style="position: relative; overflow: hidden; width: 100%; height: auto; min-height: 0px; max-height: 402px;">
<div style="position: relative; overflow: auto; margin-bottom: -15px; min-height: 15px; max-height: 417px;">
<div class="scrolling_container">
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M8 0A8 8 0 11.582 11.001h2.221a6 6 0 100-6L.582 4.999A8.003 8.003 0 018 0zM7 5l4 3-4 3-.001-2H0V7h6.999L7 5z"></path></svg>
<div class="settings_item_label bbflex">Auto-Open</div>
</div>
<div class="bbflex">
<div class="settings_toggle off" data-settings="funcaptcha_auto_open">
<div></div>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Automatically opens captcha challenges.</div>
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M13.336 9.007l.044.085 2.58 6.193a.516.516 0 01-.91.48l-.043-.083-.728-1.747h-2.753l-.727 1.747a.516.516 0 01-.586.306l-.089-.028a.516.516 0 01-.306-.586l.028-.089 2.58-6.193a.517.517 0 01.91-.085zM4.128 1.728V4.13a5.161 5.161 0 004.13 9.187v2.095A7.226 7.226 0 014.128 1.73zm8.775 8.904l-.947 2.271h1.893l-.946-2.27zM8.258 0v8.258H6.193V0h2.065zm2.065 1.728a7.233 7.233 0 014.055 5.498h-2.094a5.162 5.162 0 00-1.962-3.097V1.728z"></path></svg>
<div class="settings_item_label bbflex">Auto-Solve</div>
</div>
<div class="bbflex">
<div class="settings_toggle off" data-settings="funcaptcha_auto_solve">
<div></div>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Automatically solves captcha challenges.</div>
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M12.214 10l.964 3H14.5a1.5 1.5 0 010 3h-13a1.5 1.5 0 010-3h1.322l.964-3h8.428zm-1.607-5l.964 3H4.429l.964-3h5.214zM9 0l.964 3H6.036L7 0h2z"></path></svg>
<div class="settings_item_label bbflex">Delay solving</div>
</div>
<div class="bbflex">
<div class="settings_toggle off" data-settings="funcaptcha_solve_delay">
<div></div>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Adds a delay to avoid detection.</div>
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M16 8a8 8 0 01-8 8v-1a7 7 0 007-7h1zm-4.667 3.536l.667.707C10.976 13.33 9.562 14 8 14c-1.562 0-2.976-.671-4-1.757l.667-.707C5.52 12.441 6.698 13 8 13s2.48-.56 3.333-1.464zM7 4.5a.5.5 0 01.492.41L7.5 5v3.5H10a.5.5 0 01.492.41L10.5 9a.5.5 0 01-.41.492L10 9.5H6.5V5a.5.5 0 01.5-.5zM8 0v1a7 7 0 00-7 7H0a8 8 0 018-8zm0 2c1.562 0 2.977.672 4 1.758l-.666.707C10.48 3.56 9.302 3 8 3s-2.48.56-3.334 1.465L4 3.758C5.023 2.672 6.438 2 8 2z"></path></svg>
<div class="settings_item_label bbflex">Delay Timer</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Milliseconds to delay solving.</div>
<input type="number" autocomplete="off" spellcheck="false" placeholder="Delay" value="" class="settings_text text_input text_right small" data-settings="funcaptcha_solve_delay_time">
</div>
</div>
</div>
</div>
</div>
</div>
<!-- AWSCAPTCHA TAB -->
<div class="tab hidden" data-tab="awscaptcha">
<div class="header">
<button class="nav_icon back" data-tabtarget="main">
<svg width="12" height="12" viewBox="0 0 9 16"><path d="M2.684 8l6.038-6.308c.37-.387.37-1.015 0-1.402a.92.92 0 00-1.342 0L0 8l7.38 7.71a.92.92 0 001.342 0c.37-.387.37-1.015 0-1.402L2.684 8z"></path></svg>
</button>
<div class="header_label_container">
<div class="header_label">AWS CAPTCHA</div>
</div>
<a href="https://nopecha.com/demo/awscaptcha" target="_blank">
<button class="nav_icon">
<svg width="16" height="16" viewBox="0 0 256 310"><path d="M0 173.367l.985.52 15.49 1.762 19.455-1.082.856-.45-17.267-1.501-19.519.75z" fill="#B6C99C"/><path d="M128 .698L73.948 27.724V201.23L128 211.148l1.85-2.5V5.148L128 .699z" fill="#4C612C"/><path d="M128 .698v217.7l54.053-16.141V27.724L128 .698z" fill="#769B3F"/><path d="M219.214 174.117l.922.623 19.339 1.074 15.656-1.779.869-.669-19.52-.75-17.266 1.501z" fill="#B6C99C"/><path d="M219.214 210.153l20.27 2.627.543-.998v-35.397l-.543-1.141-20.27-1.126v36.035z" fill="#4C612C"/><path d="M36.786 210.153l-20.27 2.627-.342-.925v-36.001l.342-.61 20.27-1.126v36.035z" fill="#769B3F"/><path d="M125.748 208.651l-89.713-15.765-19.52 1.876.889.891 85.223 17.265.974-.513 22.147-3.754z" fill="#B6C99C"/><path d="M0 191.385v54.428L89.713 290.8v.055L128 310l1.6-3.002v-118.85l-1.6-3.746-38.287-3.753v28.888l-73.197-14.81v-19.483L0 173.367v18.018z" fill="#4C612C"/><path d="M128 209.026l21.771 3.754 2.804.118 85.285-17.129 1.624-1.007-19.144-1.877L128 209.026z" fill="#B6C99C"/><path d="M239.484 175.243v19.483l-73.196 14.811v-30.165L128 183.126V310l128-64.188v-72.446l-16.516 1.877z" fill="#769B3F"/><path d="M166.287 182.375L128 179.372l-38.288 3.003L128 186.13l38.287-3.754z" fill="#B6C99C"/></svg>
</button>
</a>
</div>
<div style="position: relative; overflow: hidden; width: 100%; height: auto; min-height: 0px; max-height: 402px;">
<div style="position: relative; overflow: auto; margin-bottom: -15px; min-height: 15px; max-height: 417px;">
<div class="scrolling_container">
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M8 0A8 8 0 11.582 11.001h2.221a6 6 0 100-6L.582 4.999A8.003 8.003 0 018 0zM7 5l4 3-4 3-.001-2H0V7h6.999L7 5z"></path></svg>
<div class="settings_item_label bbflex">Auto-Open</div>
</div>
<div class="bbflex">
<div class="settings_toggle off" data-settings="awscaptcha_auto_open">
<div></div>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Automatically opens captcha challenges.</div>
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M13.336 9.007l.044.085 2.58 6.193a.516.516 0 01-.91.48l-.043-.083-.728-1.747h-2.753l-.727 1.747a.516.516 0 01-.586.306l-.089-.028a.516.516 0 01-.306-.586l.028-.089 2.58-6.193a.517.517 0 01.91-.085zM4.128 1.728V4.13a5.161 5.161 0 004.13 9.187v2.095A7.226 7.226 0 014.128 1.73zm8.775 8.904l-.947 2.271h1.893l-.946-2.27zM8.258 0v8.258H6.193V0h2.065zm2.065 1.728a7.233 7.233 0 014.055 5.498h-2.094a5.162 5.162 0 00-1.962-3.097V1.728z"></path></svg>
<div class="settings_item_label bbflex">Auto-Solve</div>
</div>
<div class="bbflex">
<div class="settings_toggle off" data-settings="awscaptcha_auto_solve">
<div></div>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Automatically solves captcha challenges.</div>
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M12.214 10l.964 3H14.5a1.5 1.5 0 010 3h-13a1.5 1.5 0 010-3h1.322l.964-3h8.428zm-1.607-5l.964 3H4.429l.964-3h5.214zM9 0l.964 3H6.036L7 0h2z"></path></svg>
<div class="settings_item_label bbflex">Delay solving</div>
</div>
<div class="bbflex">
<div class="settings_toggle off" data-settings="awscaptcha_solve_delay">
<div></div>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Adds a delay to avoid detection.</div>
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M16 8a8 8 0 01-8 8v-1a7 7 0 007-7h1zm-4.667 3.536l.667.707C10.976 13.33 9.562 14 8 14c-1.562 0-2.976-.671-4-1.757l.667-.707C5.52 12.441 6.698 13 8 13s2.48-.56 3.333-1.464zM7 4.5a.5.5 0 01.492.41L7.5 5v3.5H10a.5.5 0 01.492.41L10.5 9a.5.5 0 01-.41.492L10 9.5H6.5V5a.5.5 0 01.5-.5zM8 0v1a7 7 0 00-7 7H0a8 8 0 018-8zm0 2c1.562 0 2.977.672 4 1.758l-.666.707C10.48 3.56 9.302 3 8 3s-2.48.56-3.334 1.465L4 3.758C5.023 2.672 6.438 2 8 2z"></path></svg>
<div class="settings_item_label bbflex">Delay Timer</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Milliseconds to delay solving.</div>
<input type="number" autocomplete="off" spellcheck="false" placeholder="Delay" value="" class="settings_text text_input text_right small" data-settings="awscaptcha_solve_delay_time">
</div>
</div>
</div>
</div>
</div>
</div>
<!-- TEXTCAPTCHA TAB -->
<div class="tab hidden" data-tab="textcaptcha">
<div class="header">
<button class="nav_icon back" data-tabtarget="main">
<svg width="12" height="12" viewBox="0 0 9 16"><path d="M2.684 8l6.038-6.308c.37-.387.37-1.015 0-1.402a.92.92 0 00-1.342 0L0 8l7.38 7.71a.92.92 0 001.342 0c.37-.387.37-1.015 0-1.402L2.684 8z"></path></svg>
</button>
<div class="header_label_container">
<div class="header_label">Text CAPTCHA</div>
</div>
<a href="https://nopecha.com/demo/textcaptcha" target="_blank">
<button class="nav_icon">
<svg width="16" height="16" viewBox="0 0 100 100"><g transform="translate(0,51) scale(0.01,-0.01)"><path fill="#ffffff" d="M7287.1,5007c-697.7-46.8-1170-242.5-1467.8-608.4c-227.6-285.1-274.4-463.7-170.2-655.2c89.3-159.5,185.1-202.1,574.4-259.5c234-34,310.6-14.9,425.4,114.9c331.8,370.1,385,399.9,757.3,414.8c393.6,19.1,689.2-59.6,804.1-212.7c72.3-95.7,119.1-274.4,119.1-451v-151l-174.5-55.3c-251-80.8-461.6-131.9-989.2-240.4c-908.3-185.1-1240.2-321.2-1516.7-619c-231.9-251-340.4-551-340.4-933.9C5308.8,661,5713,148.3,6404.3-34.6c119.1-31.9,223.4-40.4,521.2-38.3c342.5,0,387.2,6.4,559.5,57.4c310.6,95.7,604.1,261.7,838.1,470.1l110.6,100l44.7-144.7c59.6-193.6,125.5-289.3,238.3-344.6c80.8-38.3,131.9-44.7,363.7-44.7c363.8,0,472.3,46.8,572.2,242.5c48.9,95.7,44.7,202.1-17,502c-34.1,161.7-38.3,321.2-40.4,1531.6c-2.1,1159.4-6.4,1378.5-38.3,1552.9c-57.4,338.2-112.7,459.5-287.2,642.4c-259.5,272.3-597.8,423.3-1089.2,482.9C7974.2,4998.5,7459.4,5017.6,7287.1,5007z M8325.2,1962.9c-10.6-346.7-17-416.9-59.6-523.3c-97.9-255.3-353.1-482.9-642.4-570.1c-202.1-61.7-489.3-51.1-644.5,23.4c-134,65.9-263.8,195.7-329.7,329.7c-76.6,159.5-74.5,389.3,6.4,525.4c117,200,302.1,282.9,950.9,429.7c240.4,55.3,493.5,117,563.7,138.3c70.2,23.4,136.2,42.5,146.8,42.5C8327.4,2360.7,8329.5,2186.3,8325.2,1962.9z"/><path fill="#ffffff" d="M2909.2,1996.9c-38.3-12.8-104.2-57.4-148.9-100c-72.3-72.3-187.2-359.5-1248.7-3097.3C869.2-2861.7,333.1-4252.9,322.5-4295.5c-40.4-161.7,68.1-378.7,229.7-451c74.5-34,140.4-40.4,448.9-40.4c410.6,0,491.4,21.3,591.4,153.2c34,44.7,148.9,342.5,299.9,772.2l242.5,702h1346.6h1348.7l217-585c119.1-321.2,236.1-640.3,261.6-706.2c55.3-153.2,131.9-244.6,244.7-295.7c117-53.2,776.4-59.6,899.8-8.5c157.4,65.9,259.5,217,259.5,380.8c0,76.6-244.6,708.4-1216.8,3144.1c-1327.4,3331.3-1257.2,3171.7-1452.9,3227C3938.8,2024.6,3009.2,2024.6,2909.2,1996.9z M3945.2-851.5l444.6-1201.9l-906.2-6.4c-497.8-2.1-908.3,0-912.6,4.3c-6.4,6.4,782.8,2216.6,878.6,2459.1C3466.6,446.2,3441.1,514.2,3945.2-851.5z"/></g></svg>
</button>
</a>
</div>
<div style="position: relative; overflow: hidden; width: 100%; height: auto; min-height: 0px; max-height: 402px;">
<div style="position: relative; overflow: auto; margin-bottom: -15px; min-height: 15px; max-height: 417px;">
<div class="scrolling_container">
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M13.336 9.007l.044.085 2.58 6.193a.516.516 0 01-.91.48l-.043-.083-.728-1.747h-2.753l-.727 1.747a.516.516 0 01-.586.306l-.089-.028a.516.516 0 01-.306-.586l.028-.089 2.58-6.193a.517.517 0 01.91-.085zM4.128 1.728V4.13a5.161 5.161 0 004.13 9.187v2.095A7.226 7.226 0 014.128 1.73zm8.775 8.904l-.947 2.271h1.893l-.946-2.27zM8.258 0v8.258H6.193V0h2.065zm2.065 1.728a7.233 7.233 0 014.055 5.498h-2.094a5.162 5.162 0 00-1.962-3.097V1.728z"></path></svg>
<div class="settings_item_label bbflex">Auto-Solve</div>
</div>
<div class="bbflex">
<div class="settings_toggle off" data-settings="textcaptcha_auto_solve">
<div></div>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Automatically solves captcha challenges.</div>
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M12.214 10l.964 3H14.5a1.5 1.5 0 010 3h-13a1.5 1.5 0 010-3h1.322l.964-3h8.428zm-1.607-5l.964 3H4.429l.964-3h5.214zM9 0l.964 3H6.036L7 0h2z"></path></svg>
<div class="settings_item_label bbflex">Delay solving</div>
</div>
<div class="bbflex">
<div class="settings_toggle off" data-settings="textcaptcha_solve_delay">
<div></div>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Adds a delay to avoid detection.</div>
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M16 8a8 8 0 01-8 8v-1a7 7 0 007-7h1zm-4.667 3.536l.667.707C10.976 13.33 9.562 14 8 14c-1.562 0-2.976-.671-4-1.757l.667-.707C5.52 12.441 6.698 13 8 13s2.48-.56 3.333-1.464zM7 4.5a.5.5 0 01.492.41L7.5 5v3.5H10a.5.5 0 01.492.41L10.5 9a.5.5 0 01-.41.492L10 9.5H6.5V5a.5.5 0 01.5-.5zM8 0v1a7 7 0 00-7 7H0a8 8 0 018-8zm0 2c1.562 0 2.977.672 4 1.758l-.666.707C10.48 3.56 9.302 3 8 3s-2.48.56-3.334 1.465L4 3.758C5.023 2.672 6.438 2 8 2z"></path></svg>
<div class="settings_item_label bbflex">Delay Timer</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">Milliseconds to delay solving.</div>
<input type="number" autocomplete="off" spellcheck="false" placeholder="Delay" value="" class="settings_text text_input text_right small" data-settings="textcaptcha_solve_delay_time">
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M10.833 0C12.03 0 13 .895 13 2v2h-2V2H2v12h2v2H2.167C.97 16 0 15.105 0 14V2C0 .895.97 0 2.167 0h8.666zM9.5 5a4.5 4.5 0 013.81 6.895l2.397 2.398a1 1 0 01-1.32 1.497l-.094-.083-2.398-2.396A4.5 4.5 0 119.5 5zm0 2a2.5 2.5 0 100 5 2.5 2.5 0 000-5z"></path></svg>
<div class="settings_item_label bbflex">Image Element</div>
</div>
<div class="bbflex">
<div class="settings_button bbflex">
<div class="locate" data-key="textcaptcha_image_selector">Locate</div>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">CSS selector for the captcha image.</div>
<input type="text" autocomplete="off" spellcheck="false" placeholder="Enter CSS selector" value="" class="settings_text text_input text_right" data-settings="textcaptcha_image_selector">
</div>
</div>
<div class="settings_item_container">
<div class="settings_item">
<div class="bbflex">
<div class="bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M10.833 0C12.03 0 13 .895 13 2v2h-2V2H2v12h2v2H2.167C.97 16 0 15.105 0 14V2C0 .895.97 0 2.167 0h8.666zM9.5 5a4.5 4.5 0 013.81 6.895l2.397 2.398a1 1 0 01-1.32 1.497l-.094-.083-2.398-2.396A4.5 4.5 0 119.5 5zm0 2a2.5 2.5 0 100 5 2.5 2.5 0 000-5z"></path></svg>
<div class="settings_item_label bbflex">Input Element</div>
</div>
<div class="bbflex">
<div class="settings_button bbflex">
<div class="locate" data-key="textcaptcha_input_selector">Locate</div>
</div>
</div>
</div>
</div>
<div class="settings_description_container bbflex">
<div class="settings_description">CSS selector for the captcha input.</div>
<input type="text" autocomplete="off" spellcheck="false" placeholder="Enter CSS selector" value="" class="settings_text text_input text_right" data-settings="textcaptcha_input_selector">
</div>
</div>
</div>
</div>
</div>
</div>
<!-- MAIN TAB -->
<div class="tab" data-tab="main">
<div class="header">
<!-- <a href="https://nopecha.com/discord" target="_blank">
<button class="nav_icon hover_glow">
<svg width="18" height="18" viewBox="0 0 71 55"><path d="M60.1045 4.8978C55.5792 2.8214 50.7265 1.2916 45.6527 0.41542C45.5603 0.39851 45.468 0.440769 45.4204 0.525289C44.7963 1.6353 44.105 3.0834 43.6209 4.2216C38.1637 3.4046 32.7345 3.4046 27.3892 4.2216C26.905 3.0581 26.1886 1.6353 25.5617 0.525289C25.5141 0.443589 25.4218 0.40133 25.3294 0.41542C20.2584 1.2888 15.4057 2.8186 10.8776 4.8978C10.8384 4.9147 10.8048 4.9429 10.7825 4.9795C1.57795 18.7309 -0.943561 32.1443 0.293408 45.3914C0.299005 45.4562 0.335386 45.5182 0.385761 45.5576C6.45866 50.0174 12.3413 52.7249 18.1147 54.5195C18.2071 54.5477 18.305 54.5139 18.3638 54.4378C19.7295 52.5728 20.9469 50.6063 21.9907 48.5383C22.0523 48.4172 21.9935 48.2735 21.8676 48.2256C19.9366 47.4931 18.0979 46.6 16.3292 45.5858C16.1893 45.5041 16.1781 45.304 16.3068 45.2082C16.679 44.9293 17.0513 44.6391 17.4067 44.3461C17.471 44.2926 17.5606 44.2813 17.6362 44.3151C29.2558 49.6202 41.8354 49.6202 53.3179 44.3151C53.3935 44.2785 53.4831 44.2898 53.5502 44.3433C53.9057 44.6363 54.2779 44.9293 54.6529 45.2082C54.7816 45.304 54.7732 45.5041 54.6333 45.5858C52.8646 46.6197 51.0259 47.4931 49.0921 48.2228C48.9662 48.2707 48.9102 48.4172 48.9718 48.5383C50.038 50.6034 51.2554 52.5699 52.5959 54.435C52.6519 54.5139 52.7526 54.5477 52.845 54.5195C58.6464 52.7249 64.529 50.0174 70.6019 45.5576C70.6551 45.5182 70.6887 45.459 70.6943 45.3942C72.1747 30.0791 68.2147 16.7757 60.1968 4.9823C60.1772 4.9429 60.1437 4.9147 60.1045 4.8978ZM23.7259 37.3253C20.2276 37.3253 17.3451 34.1136 17.3451 30.1693C17.3451 26.225 20.1717 23.0133 23.7259 23.0133C27.308 23.0133 30.1626 26.2532 30.1066 30.1693C30.1066 34.1136 27.28 37.3253 23.7259 37.3253ZM47.3178 37.3253C43.8196 37.3253 40.9371 34.1136 40.9371 30.1693C40.9371 26.225 43.7636 23.0133 47.3178 23.0133C50.9 23.0133 53.7545 26.2532 53.6986 30.1693C53.6986 34.1136 50.9 37.3253 47.3178 37.3253Z"/></svg>
</button>
</a> -->
<div data-tabtarget="settings">
<button class="nav_icon">
<svg width="12" height="12" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M1 0h14a1 1 0 010 2H1a1 1 0 110-2zm0 6h14a1 1 0 010 2H1a1 1 0 110-2zm0 6h14a1 1 0 010 2H1a1 1 0 010-2z" opacity="0.603"></path></svg>
</button>
</div>
<div class="header_label_container">
<a href="https://nopecha.com" target="_blank">
<div class="header_label">NopeCHA</div>
</a>
</div>
<button id='power' class="nav_icon">
<div style="width: 32px; height: 32px;">
<div class="btn">
<svg width="32" height="32" viewBox="0 0 72 72"><path d="M31.5 18.57a18 18 0 109-.01v3.13a15 15 0 11-9 0v-3.12zm3-5.07v22a1.5 1.5 0 003 0v-22a1.5 1.5 0 00-3 0zM36 66a30 30 0 110-60 30 30 0 010 60z" fill="#ffffff"></path></svg>
</div>
</div>
<div class="btn_outline spinning hidden">
<svg width="32" height="32" viewBox="0 0 72 72"><path fill="#A0FEDA" fill-rule="evenodd" d="M.055 38H3.06C4.093 55.294 18.446 69 36 69s31.907-13.706 32.94-31h3.005C70.908 56.952 55.211 72 36 72S1.092 56.952.055 38zm0-4C1.092 15.048 16.789 0 36 0s34.908 15.048 35.945 34H68.94C67.907 16.706 53.554 3 36 3S4.093 16.706 3.06 34H.055z"></path></svg>
</div>
<div class="btn_outline static hidden">
<svg width="32" height="32" viewBox="0 0 72 72" fill="#55ff8a"><path d="M36 72C16.118 72 0 55.882 0 36S16.118 0 36 0s36 16.118 36 36-16.118 36-36 36zm0-3c18.225 0 33-14.775 33-33S54.225 3 36 3 3 17.775 3 36s14.775 33 33 33z"></path></svg>
</div>
</button>
</div>
<div class="plan_info_container" style="border-bottom: 1px solid rgba(255, 255, 255, 0.4);">
<input type="text" autocomplete="off" spellcheck="false" placeholder="Enter subscription key" value="" class="settings_text text_input plan_info hiddenleft" data-settings="key" style="padding: 2px 8px 2px 16px">
<div id="edit_key" class="plan_info">
<div class="plan_label clickable key_label">
<div>Subscription Key</div>
<div class="instructions">(Click to enter)</div>
</div>
<div class="plan_value">
<button class="plan_button edit_icon hidden clickable">
<!-- <div class="edit_key"></div> -->
<svg width="16" height="16" fill="#ffffff"><path fill-rule="evenodd" d="M11 0l.217.005a5 5 0 014.778 4.772L16 5 5 16H0v-5L11 0zM2 11.828V14h2.172l9.737-9.737a3.009 3.009 0 00-1.983-2.125l-.184-.052L2 11.828z"></path></svg>
</button>
</div>
</div>
</div>
<br>
<div class="plan_info_box">
<div id="ipbanned_warning" class="warning_box hidden">
<div>Your IP is ineligible for free credits.</div>
<div><a href="https://nopecha.com/pricing" target="_blank">Purchase a key</a> to use with VPN/proxy.</div>
</div>
<div class="plan_info_container">
<div class="plan_info">
<div id="plan" class="plan_label">Free Plan</div>
<div class="plan_value">
<a href="https://nopecha.com/manage" target="_blank">
<button class="plan_button link">
<div class="plan_button_label clickable">Upgrade</div>
</button>
</a>
</div>
</div>
</div>
<div class="plan_info_container">
<div class="plan_info">
<div class="plan_label">Credits</div>
<div class="plan_value">
<a href="https://nopecha.com/manage" target="_blank">
<button class="plan_button link">
<div id="credit" class="plan_button_label clickable">0 / 0</div>
</button>
</a>
</div>
</div>
</div>
<div class="plan_info_container">
<div class="plan_info">
<div class="plan_label">Refills</div>
<div class="plan_value">
<a href="https://nopecha.com/manage" target="_blank">
<button class="plan_button link">
<div id="refills" class="plan_button_label clickable">00:00:00</div>
</button>
</a>
</div>
</div>
</div>
</div>
<div class="menu">
<button class="menu_item_container" data-tabtarget="hcaptcha">
<div class="button_label_container">
<svg width="16" height="16" viewBox="20 20 560 560"><path d="m374.48 524.29h74.9v74.89h-74.9z" fill="#0074bf" opacity=".502"/><path d="m299.59 524.29h74.89v74.89h-74.89zm-74.89 0h74.89v74.89h-74.89z" fill="#0074bf" opacity=".702"/><path d="m149.8 524.29h74.9v74.89h-74.9z" fill="#0074bf" opacity=".502"/><g fill="#0082bf"><path d="m449.39 449.39h74.9v74.9h-74.9z" opacity=".702"/><path d="m374.48 449.39h74.9v74.9h-74.9z" opacity=".8"/><path d="m299.59 449.39h74.89v74.9h-74.89zm-74.89 0h74.89v74.9h-74.89z"/><path d="m149.8 449.39h74.9v74.9h-74.9z" opacity=".8"/><path d="m74.89 449.39h74.9v74.9h-74.9z" opacity=".702"/></g><g fill="#008fbf"><path d="m524.29 374.48h74.89v74.9h-74.89z" opacity=".502"/><path d="m449.39 374.48h74.9v74.9h-74.9z" opacity=".8"/><path d="m374.48 374.48h74.9v74.9h-74.9zm-74.89 0h74.89v74.9h-74.89zm-74.89 0h74.89v74.9h-74.89z"/><path d="m149.8 374.48h74.9v74.9h-74.9z"/><path d="m74.89 374.48h74.9v74.9h-74.9z" opacity=".8"/><path d="m0 374.48h74.89v74.9h-74.89z" opacity=".502"/></g><path d="m524.29 299.59h74.89v74.89h-74.89z" fill="#009dbf" opacity=".702"/><path d="m449.39 299.59h74.9v74.89h-74.9zm-74.91 0h74.9v74.89h-74.9zm-74.89 0h74.89v74.89h-74.89zm-74.89 0h74.89v74.89h-74.89z" fill="#009dbf"/><path d="m149.8 299.59h74.9v74.89h-74.9zm-74.91 0h74.9v74.89h-74.9z" fill="#009dbf"/><path d="m0 299.59h74.89v74.89h-74.89z" fill="#009dbf" opacity=".702"/><path d="m524.29 224.7h74.89v74.89h-74.89z" fill="#00abbf" opacity=".702"/><path d="m449.39 224.7h74.9v74.89h-74.9zm-74.91 0h74.9v74.89h-74.9zm-74.89 0h74.89v74.89h-74.89zm-74.89 0h74.89v74.89h-74.89z" fill="#00abbf"/><path d="m149.8 224.7h74.9v74.89h-74.9zm-74.91 0h74.9v74.89h-74.9z" fill="#00abbf"/><path d="m0 224.7h74.89v74.89h-74.89z" fill="#00abbf" opacity=".702"/><g fill="#00b9bf"><path d="m524.29 149.8h74.89v74.9h-74.89z" opacity=".502"/><path d="m449.39 149.8h74.9v74.9h-74.9z" opacity=".8"/><path d="m374.48 149.8h74.9v74.9h-74.9zm-74.89 0h74.89v74.9h-74.89zm-74.89 0h74.89v74.9h-74.89z"/><path d="m149.8 149.8h74.9v74.9h-74.9z"/><path d="m74.89 149.8h74.9v74.9h-74.9z" opacity=".8"/><path d="m0 149.8h74.89v74.9h-74.89z" opacity=".502"/></g><g fill="#00c6bf"><path d="m449.39 74.89h74.9v74.9h-74.9z" opacity=".702"/><path d="m374.48 74.89h74.9v74.9h-74.9z" opacity=".8"/><path d="m299.59 74.89h74.89v74.9h-74.89zm-74.89 0h74.89v74.9h-74.89z"/><path d="m149.8 74.89h74.9v74.9h-74.9z" opacity=".8"/><path d="m74.89 74.89h74.9v74.9h-74.9z" opacity=".702"/></g><path d="m374.48 0h74.9v74.89h-74.9z" fill="#00d4bf" opacity=".502"/><path d="m299.59 0h74.89v74.89h-74.89zm-74.89 0h74.89v74.89h-74.89z" fill="#00d4bf" opacity=".702"/><path d="m149.8 0h74.9v74.89h-74.9z" fill="#00d4bf" opacity=".502"/><path d="m197.2 275.96 20.87-46.71c7.61-11.97 6.6-26.64-1.72-34.96-.28-.28-.56-.55-.86-.81-.29-.26-.59-.52-.89-.76a21.043 21.043 0 0 0 -1.92-1.37 22.68 22.68 0 0 0 -4.51-2.13c-1.58-.55-3.21-.92-4.87-1.12-1.66-.19-3.34-.2-5-.03s-3.3.51-4.88 1.04c-1.79.55-3.53 1.27-5.19 2.13a32.32 32.32 0 0 0 -4.72 3.02 32.38 32.38 0 0 0 -4.12 3.82 32 32 0 0 0 -3.37 4.48c-.98 1.59-28.57 66.66-39.2 96.62s-6.39 84.91 34.61 125.99c43.48 43.48 106.43 53.41 146.58 23.28.42-.21.84-.44 1.24-.67.41-.23.81-.48 1.2-.74.4-.25.78-.52 1.16-.8.38-.27.75-.56 1.11-.86l123.73-103.32c6.01-4.97 14.9-15.2 6.92-26.88-7.79-11.39-22.55-3.64-28.57.21l-71.21 51.78c-.33.27-.72.48-1.13.6-.42.12-.85.16-1.28.11s-.85-.19-1.22-.4c-.38-.21-.71-.5-.97-.85-1.81-2.22-2.13-8.11.71-10.44l109.16-92.64c9.43-8.49 10.74-20.84 3.1-29.3-7.45-8.29-19.29-8.04-28.8.53l-98.28 76.83c-.46.38-.99.66-1.56.82s-1.17.21-1.76.13-1.15-.27-1.66-.58c-.51-.3-.96-.7-1.3-1.18-1.94-2.18-2.69-5.89-.5-8.07l111.3-108.01c2.09-1.95 3.78-4.29 4.96-6.88 1.18-2.6 1.85-5.41 1.95-8.26s-.36-5.7-1.36-8.37c-1-2.68-2.51-5.13-4.45-7.22-.97-1.03-2.05-1.95-3.2-2.75a21.14 21.14 0 0 0 -3.69-2.05c-1.3-.55-2.65-.97-4.03-1.26-1.38-.28-2.79-.42-4.2-.41-1.44-.02-2.88.1-4.29.37a21.906 21.906 0 0 0 -7.96 3.16c-1.21.78-2.34 1.68-3.38 2.68l-113.73 106.83c-2.72 2.72-8.04 0-8.69-3.18-.06-.28-.08-.57-.07-.86s.06-.58.15-.85c.08-.28.2-.55.35-.79.15-.25.33-.48.54-.68l87.05-99.12a21.38 21.38 0 0 0 6.82-15.3c.11-5.81-2.15-11.42-6.25-15.53-4.11-4.12-9.71-6.4-15.52-6.31s-11.34 2.53-15.32 6.77l-132.01 145.95c-4.73 4.73-11.7 4.97-15.02 2.22-.51-.4-.93-.9-1.24-1.46-.32-.56-.52-1.18-.6-1.82-.08-.65-.03-1.3.14-1.92s.46-1.21.85-1.72z" fill="#fff"/></svg>
<div class="button_label">hCaptcha</div>
</div>
<div class="icon-container">
<svg viewBox="0 0 16 16" class="menu_item_arrow"><path fill-rule="evenodd" d="M10.3 8l-6-6.3a1 1 0 010-1.4 1 1 0 011.3 0L13 8l-7.4 7.7a1 1 0 01-1.3 0 1 1 0 010-1.4l6-6.3z"></path></svg>
</div>
</button>
<button class="menu_item_container" data-tabtarget="recaptcha">
<div class="button_label_container">
<svg width="16" height="16" viewBox="0 0 70 70"><path d="M64 31.955l-.033-1.37V4.687l-7.16 7.16C50.948 4.674 42.033.093 32.05.093c-10.4 0-19.622 4.96-25.458 12.64l11.736 11.86a15.55 15.55 0 0 1 4.754-5.334c2.05-1.6 4.952-2.906 8.968-2.906.485 0 .86.057 1.135.163 4.976.393 9.288 3.14 11.828 7.124l-8.307 8.307L64 31.953" fill="#1c3aa9"/><path d="M31.862.094l-1.37.033H4.594l7.16 7.16C4.58 13.147 0 22.06 0 32.046c0 10.4 4.96 19.622 12.64 25.458L24.5 45.768a15.55 15.55 0 0 1-5.334-4.754c-1.6-2.05-2.906-4.952-2.906-8.968 0-.485.057-.86.163-1.135.393-4.976 3.14-9.288 7.124-11.828l8.307 8.307L31.86.095" fill="#4285f4"/><path d="M.001 32.045l.033 1.37v25.898l7.16-7.16c5.86 7.173 14.774 11.754 24.76 11.754 10.4 0 19.622-4.96 25.458-12.64l-11.736-11.86a15.55 15.55 0 0 1-4.754 5.334c-2.05 1.6-4.952 2.906-8.968 2.906-.485 0-.86-.057-1.135-.163-4.976-.393-9.288-3.14-11.828-7.124l8.307-8.307c-10.522.04-22.4.066-27.295-.005" fill="#ababab"/></svg>
<div class="button_label">reCAPTCHA</div>
</div>
<div class="icon-container">
<svg viewBox="0 0 16 16" class="menu_item_arrow"><path fill-rule="evenodd" d="M10.3 8l-6-6.3a1 1 0 010-1.4 1 1 0 011.3 0L13 8l-7.4 7.7a1 1 0 01-1.3 0 1 1 0 010-1.4l6-6.3z"></path></svg>
</div>
</button>
<button class="menu_item_container" data-tabtarget="funcaptcha">
<div class="button_label_container">
<svg width="16" height="16" viewBox="18 30 37 34"><path d="M52.107,37.991,38.249,30a3.992,3.992,0,0,0-1.919-.533A3.606,3.606,0,0,0,34.412,30L20.555,37.991a3.829,3.829,0,0,0-1.919,3.3V57.338a3.9,3.9,0,0,0,1.919,3.3l.959.533,4.423,2.558V56.326l10.393-5.969,10.393,5.969v7.355l4.423-2.558.959-.586a3.829,3.829,0,0,0,1.919-3.3V41.243A3.857,3.857,0,0,0,52.107,37.991ZM46.617,47.9,38.2,43a3.99,3.99,0,0,0-1.918-.533A3.607,3.607,0,0,0,34.359,43l-8.474,4.9V43.268l8.688-5.01a3.425,3.425,0,0,1,3.358,0l8.688,5.01Z" fill="#50b95d"/></svg>
<div class="button_label">FunCAPTCHA</div>
</div>
<div class="icon-container">
<svg viewBox="0 0 16 16" class="menu_item_arrow"><path fill-rule="evenodd" d="M10.3 8l-6-6.3a1 1 0 010-1.4 1 1 0 011.3 0L13 8l-7.4 7.7a1 1 0 01-1.3 0 1 1 0 010-1.4l6-6.3z"></path></svg>
</div>
</button>
<button class="menu_item_container" data-tabtarget="awscaptcha">
<div class="button_label_container">
<svg width="16" height="16" viewBox="0 0 256 310"><path d="M0 173.367l.985.52 15.49 1.762 19.455-1.082.856-.45-17.267-1.501-19.519.75z" fill="#B6C99C"/><path d="M128 .698L73.948 27.724V201.23L128 211.148l1.85-2.5V5.148L128 .699z" fill="#4C612C"/><path d="M128 .698v217.7l54.053-16.141V27.724L128 .698z" fill="#769B3F"/><path d="M219.214 174.117l.922.623 19.339 1.074 15.656-1.779.869-.669-19.52-.75-17.266 1.501z" fill="#B6C99C"/><path d="M219.214 210.153l20.27 2.627.543-.998v-35.397l-.543-1.141-20.27-1.126v36.035z" fill="#4C612C"/><path d="M36.786 210.153l-20.27 2.627-.342-.925v-36.001l.342-.61 20.27-1.126v36.035z" fill="#769B3F"/><path d="M125.748 208.651l-89.713-15.765-19.52 1.876.889.891 85.223 17.265.974-.513 22.147-3.754z" fill="#B6C99C"/><path d="M0 191.385v54.428L89.713 290.8v.055L128 310l1.6-3.002v-118.85l-1.6-3.746-38.287-3.753v28.888l-73.197-14.81v-19.483L0 173.367v18.018z" fill="#4C612C"/><path d="M128 209.026l21.771 3.754 2.804.118 85.285-17.129 1.624-1.007-19.144-1.877L128 209.026z" fill="#B6C99C"/><path d="M239.484 175.243v19.483l-73.196 14.811v-30.165L128 183.126V310l128-64.188v-72.446l-16.516 1.877z" fill="#769B3F"/><path d="M166.287 182.375L128 179.372l-38.288 3.003L128 186.13l38.287-3.754z" fill="#B6C99C"/></svg>
<div class="button_label">AWS CAPTCHA</div>
</div>
<div class="icon-container">
<svg viewBox="0 0 16 16" class="menu_item_arrow"><path fill-rule="evenodd" d="M10.3 8l-6-6.3a1 1 0 010-1.4 1 1 0 011.3 0L13 8l-7.4 7.7a1 1 0 01-1.3 0 1 1 0 010-1.4l6-6.3z"></path></svg>
</div>
</button>
<button class="menu_item_container" data-tabtarget="textcaptcha">
<div class="button_label_container">
<svg width="16" height="16" viewBox="0 0 100 100"><g transform="translate(0,51) scale(0.01,-0.01)"><path fill="#ffffff" d="M7287.1,5007c-697.7-46.8-1170-242.5-1467.8-608.4c-227.6-285.1-274.4-463.7-170.2-655.2c89.3-159.5,185.1-202.1,574.4-259.5c234-34,310.6-14.9,425.4,114.9c331.8,370.1,385,399.9,757.3,414.8c393.6,19.1,689.2-59.6,804.1-212.7c72.3-95.7,119.1-274.4,119.1-451v-151l-174.5-55.3c-251-80.8-461.6-131.9-989.2-240.4c-908.3-185.1-1240.2-321.2-1516.7-619c-231.9-251-340.4-551-340.4-933.9C5308.8,661,5713,148.3,6404.3-34.6c119.1-31.9,223.4-40.4,521.2-38.3c342.5,0,387.2,6.4,559.5,57.4c310.6,95.7,604.1,261.7,838.1,470.1l110.6,100l44.7-144.7c59.6-193.6,125.5-289.3,238.3-344.6c80.8-38.3,131.9-44.7,363.7-44.7c363.8,0,472.3,46.8,572.2,242.5c48.9,95.7,44.7,202.1-17,502c-34.1,161.7-38.3,321.2-40.4,1531.6c-2.1,1159.4-6.4,1378.5-38.3,1552.9c-57.4,338.2-112.7,459.5-287.2,642.4c-259.5,272.3-597.8,423.3-1089.2,482.9C7974.2,4998.5,7459.4,5017.6,7287.1,5007z M8325.2,1962.9c-10.6-346.7-17-416.9-59.6-523.3c-97.9-255.3-353.1-482.9-642.4-570.1c-202.1-61.7-489.3-51.1-644.5,23.4c-134,65.9-263.8,195.7-329.7,329.7c-76.6,159.5-74.5,389.3,6.4,525.4c117,200,302.1,282.9,950.9,429.7c240.4,55.3,493.5,117,563.7,138.3c70.2,23.4,136.2,42.5,146.8,42.5C8327.4,2360.7,8329.5,2186.3,8325.2,1962.9z"/><path fill="#ffffff" d="M2909.2,1996.9c-38.3-12.8-104.2-57.4-148.9-100c-72.3-72.3-187.2-359.5-1248.7-3097.3C869.2-2861.7,333.1-4252.9,322.5-4295.5c-40.4-161.7,68.1-378.7,229.7-451c74.5-34,140.4-40.4,448.9-40.4c410.6,0,491.4,21.3,591.4,153.2c34,44.7,148.9,342.5,299.9,772.2l242.5,702h1346.6h1348.7l217-585c119.1-321.2,236.1-640.3,261.6-706.2c55.3-153.2,131.9-244.6,244.7-295.7c117-53.2,776.4-59.6,899.8-8.5c157.4,65.9,259.5,217,259.5,380.8c0,76.6-244.6,708.4-1216.8,3144.1c-1327.4,3331.3-1257.2,3171.7-1452.9,3227C3938.8,2024.6,3009.2,2024.6,2909.2,1996.9z M3945.2-851.5l444.6-1201.9l-906.2-6.4c-497.8-2.1-908.3,0-912.6,4.3c-6.4,6.4,782.8,2216.6,878.6,2459.1C3466.6,446.2,3441.1,514.2,3945.2-851.5z"/></g></svg>
<div class="button_label">Text CAPTCHA</div>
</div>
<div class="icon-container">
<svg viewBox="0 0 16 16" class="menu_item_arrow"><path fill-rule="evenodd" d="M10.3 8l-6-6.3a1 1 0 010-1.4 1 1 0 011.3 0L13 8l-7.4 7.7a1 1 0 01-1.3 0 1 1 0 010-1.4l6-6.3z"></path></svg>
</div>
</button>
</div>
<div class='footer'>
<!-- <div>Join us on <a href="https://nopecha.com/discord">Discord</a> for more credits!</div>
<div id="export" class="hidden">Export Settings</div> -->
</div>
</div>
<!-- SETTINGS TAB -->
<div class="tab hidden" data-tab="settings">
<div class="header">
<button class="nav_icon back" data-tabtarget="main">
<svg width="12" height="12" viewBox="0 0 9 16"><path d="M2.684 8l6.038-6.308c.37-.387.37-1.015 0-1.402a.92.92 0 00-1.342 0L0 8l7.38 7.71a.92.92 0 001.342 0c.37-.387.37-1.015 0-1.402L2.684 8z"></path></svg>
</button>
<div class="header_label_container">
<div class="header_label">Settings</div>
</div>
<button class="nav_icon" disabled></button>
</div>
<div class="menu">
<button class="menu_item_container" data-tabtarget="disabled_hosts">
<div class="button_label_container">
<svg width="16" height="16"><path fill-rule="evenodd" d="M3 2v12h10V2H3zm0-2h10a2 2 0 012 2v12a2 2 0 01-2 2H3a2 2 0 01-2-2V2a2 2 0 012-2zm2 4h6v2H5V4zm0 4h3v2H5V8z"></path></svg>
<div class="button_label">Disabled Hosts</div>
</div>
<div class="icon-container">
<svg viewBox="0 0 16 16" class="menu_item_arrow"><path fill-rule="evenodd" d="M10.3 8l-6-6.3a1 1 0 010-1.4 1 1 0 011.3 0L13 8l-7.4 7.7a1 1 0 01-1.3 0 1 1 0 010-1.4l6-6.3z"></path></svg>
</div>
</button>
<button id="export" class="menu_item_container hidden">
<div class="button_label_container">
<svg width="16" height="16" fill="#ffffff"><path d="M8 0A8 8 0 11.582 11.001h2.221a6 6 0 100-6L.582 4.999A8.003 8.003 0 018 0zM7 5l4 3-4 3-.001-2H0V7h6.999L7 5z"></path></svg>
<div class="button_label">Export Settings</div>
</div>
<div class="icon-container">
<svg viewBox="0 0 16 16" class="menu_item_arrow"><path fill-rule="evenodd" d="M10.3 8l-6-6.3a1 1 0 010-1.4 1 1 0 011.3 0L13 8l-7.4 7.7a1 1 0 01-1.3 0 1 1 0 010-1.4l6-6.3z"></path></svg>
</div>
</button>
</div>
<!-- LINKS -->
<div style="position: relative; overflow: hidden; width: 100%; height: auto; min-height: 0px; max-height: 402px;">
<div style="position: relative; overflow: auto; margin-bottom: -15px; min-height: 15px; max-height: 417px;">
<div class="scrolling_container">
<div style="margin-top: 16px; margin-bottom: 8px; padding-bottom: 4px; font-size: 14px; font-weight: bold; border-bottom: 1px solid rgba(255, 255, 255, 0.5);">
Links
</div>
<div class="settings_item_container">
<a href="https://developers.nopecha.com" target="_blank">
<div class="settings_description_container bbflex">
<svg width="16" height="16" fill="#ffffff"><path d="M14 2.894a3.898 3.898 0 00-4.808-.126L8 3.653l-1.192-.885A3.898 3.898 0 002 2.894v9.716a7.676 7.676 0 016.006.864A7.705 7.705 0 0114 12.621V2.894zm2 10.584v1.687l-.66.275a5.652 5.652 0 00-1.34-.72V12.62c.695.187 1.37.472 2 .857zM0 2.027l.403-.387A5.898 5.898 0 018 1.162a5.898 5.898 0 017.597.478l.403.387V16a5.692 5.692 0 00-8 0 5.663 5.663 0 00-8 0V2.027zm7-.019h2v12H7v-12z"></path></svg>
<div class="settings_description">Documentation</div>
</div>
</a>
</div>
<div class="settings_item_container">
<a href="https://nopecha.com" target="_blank">
<div class="settings_description_container bbflex">
<svg width="16" height="16" viewBox="2 2 22 22" fill="#ffffff"><path d="M 12 2.0996094 L 1 12 L 4 12 L 4 21 L 11 21 L 11 15 L 13 15 L 13 21 L 20 21 L 20 12 L 23 12 L 12 2.0996094 z M 12 4.7910156 L 18 10.191406 L 18 11 L 18 19 L 15 19 L 15 13 L 9 13 L 9 19 L 6 19 L 6 10.191406 L 12 4.7910156 z"/></svg>
<div class="settings_description">Homepage</div>
</div>
</a>
</div>
<div class="settings_item_container">
<a href="https://nopecha.com/discord" target="_blank">
<div class="settings_description_container bbflex">
<svg width="16" height="16" viewBox="0 0 71 55" fill="#ffffff"><path d="M60.1045 4.8978C55.5792 2.8214 50.7265 1.2916 45.6527 0.41542C45.5603 0.39851 45.468 0.440769 45.4204 0.525289C44.7963 1.6353 44.105 3.0834 43.6209 4.2216C38.1637 3.4046 32.7345 3.4046 27.3892 4.2216C26.905 3.0581 26.1886 1.6353 25.5617 0.525289C25.5141 0.443589 25.4218 0.40133 25.3294 0.41542C20.2584 1.2888 15.4057 2.8186 10.8776 4.8978C10.8384 4.9147 10.8048 4.9429 10.7825 4.9795C1.57795 18.7309 -0.943561 32.1443 0.293408 45.3914C0.299005 45.4562 0.335386 45.5182 0.385761 45.5576C6.45866 50.0174 12.3413 52.7249 18.1147 54.5195C18.2071 54.5477 18.305 54.5139 18.3638 54.4378C19.7295 52.5728 20.9469 50.6063 21.9907 48.5383C22.0523 48.4172 21.9935 48.2735 21.8676 48.2256C19.9366 47.4931 18.0979 46.6 16.3292 45.5858C16.1893 45.5041 16.1781 45.304 16.3068 45.2082C16.679 44.9293 17.0513 44.6391 17.4067 44.3461C17.471 44.2926 17.5606 44.2813 17.6362 44.3151C29.2558 49.6202 41.8354 49.6202 53.3179 44.3151C53.3935 44.2785 53.4831 44.2898 53.5502 44.3433C53.9057 44.6363 54.2779 44.9293 54.6529 45.2082C54.7816 45.304 54.7732 45.5041 54.6333 45.5858C52.8646 46.6197 51.0259 47.4931 49.0921 48.2228C48.9662 48.2707 48.9102 48.4172 48.9718 48.5383C50.038 50.6034 51.2554 52.5699 52.5959 54.435C52.6519 54.5139 52.7526 54.5477 52.845 54.5195C58.6464 52.7249 64.529 50.0174 70.6019 45.5576C70.6551 45.5182 70.6887 45.459 70.6943 45.3942C72.1747 30.0791 68.2147 16.7757 60.1968 4.9823C60.1772 4.9429 60.1437 4.9147 60.1045 4.8978ZM23.7259 37.3253C20.2276 37.3253 17.3451 34.1136 17.3451 30.1693C17.3451 26.225 20.1717 23.0133 23.7259 23.0133C27.308 23.0133 30.1626 26.2532 30.1066 30.1693C30.1066 34.1136 27.28 37.3253 23.7259 37.3253ZM47.3178 37.3253C43.8196 37.3253 40.9371 34.1136 40.9371 30.1693C40.9371 26.225 43.7636 23.0133 47.3178 23.0133C50.9 23.0133 53.7545 26.2532 53.6986 30.1693C53.6986 34.1136 50.9 37.3253 47.3178 37.3253Z"/></svg>
<div class="settings_description">Discord</div>
</div>
</a>
</div>
<div class="settings_item_container">
<a href="https://nopecha.com/github" target="_blank">
<div class="settings_description_container bbflex">
<svg width="16" height="16" viewBox="0 0 24 24" fill="#ffffff"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
<div class="settings_description">GitHub</div>
</div>
</a>
</div>
</div>
</div>
</div>
<div class='footer'></div>
</div>
<!-- DISABLED HOSTS TAB -->
<div class="tab hidden" data-tab="disabled_hosts">
<div class="header">
<button class="nav_icon back" data-tabtarget="settings">
<svg width="12" height="12" viewBox="0 0 9 16"><path d="M2.684 8l6.038-6.308c.37-.387.37-1.015 0-1.402a.92.92 0 00-1.342 0L0 8l7.38 7.71a.92.92 0 001.342 0c.37-.387.37-1.015 0-1.402L2.684 8z"></path></svg>
</button>
<div class="header_label_container">
<div class="header_label">Disabled Hosts</div>
</div>
<button class="nav_icon" disabled></button>
</div>
<div style="position: relative; overflow: hidden; width: 100%; height: auto; min-height: 0px; max-height: 402px;">
<div style="position: relative; overflow: auto; margin-bottom: -15px; min-height: 15px; max-height: 417px;">
<div class="scrolling_container">
<div class="css-rghnfo">
<div class="settings_item_header">Current Page</div>
<div class="settings_item_container list_item">
<div class="list_item_row">
<div id="current_page_host">-</div>
<button id="add_current_page_host" class="list_item_button">
<svg width="16" height="16"><path fill="rgb(0, 106, 255)" fill-rule="evenodd" d="M9 7h6a1 1 0 110 2H9v6a1 1 0 11-2 0V9H1a1 1 0 110-2h6V1a1 1 0 112 0v6z"></path></svg>
</button>
</div>
</div>
</div>
<div>
<div class="settings_item_header">Disabled Hosts</div>
<div id="disabled_hosts"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="utils.js"></script>
<script src="content.js"></script>
<script src="popup.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -0,0 +1 @@
(async()=>{function e(){var e="true"===document.querySelector(".recaptcha-checkbox")?.getAttribute("aria-checked"),t=document.querySelector("#recaptcha-verify-button")?.disabled;return e||t}function d(r=15e3){return new Promise(async e=>{for(var t=Time.time();;){var a=document.querySelectorAll(".rc-imageselect-tile"),c=document.querySelectorAll(".rc-imageselect-dynamic-selected");if(0<a.length&&0===c.length)return e(!0);if(Time.time()-t>r)return e(!1);await Time.sleep(100)}})}let p=null;function a(e=500){return new Promise(m=>{let h=!1;const f=setInterval(async()=>{if(!h){h=!0;var c=document.querySelector(".rc-imageselect-instructions")?.innerText?.split("\n"),r=await async function(e){let t=null;return(t=1<e.length?(t=e.slice(0,2).join(" ")).replace(/\s+/g," ")?.trim():t.join("\n"))||null}(c);if(r){var c=3===c.length,i=document.querySelectorAll("table tr td");if(9===i.length||16===i.length){var l=[],n=Array(i.length).fill(null);let e=null,t=!1,a=0;for(const u of i){var o=u?.querySelector("img");if(!o)return void(h=!1);var s=o?.src?.trim();if(!s||""===s)return void(h=!1);300<=o.naturalWidth?e=s:100==o.naturalWidth&&(n[a]=s,t=!0),l.push(u),a++}t&&(e=null);i=JSON.stringify([e,n]);if(p!==i)return p=i,clearInterval(f),h=!1,m({task:r,is_hard:c,cells:l,background_url:e,urls:n})}}h=!1}},e)})}async function t(){!0===await BG.exec("Cache.get",{name:"recaptcha_widget_visible",tab_specific:!0})&&(e()?r=r||!0:(r=!1,await Time.sleep(500),document.querySelector("#recaptcha-anchor")?.click()))}async function c(){var c=await BG.exec("Cache.get",{name:"recaptcha_image_visible",tab_specific:!0});if(!0===c&&(null===document.querySelector(".rc-doscaptcha-header")&&!e()))if(g=!(g||!function(){for(const e of[".rc-imageselect-incorrect-response"])if(""===document.querySelector(e)?.style.display)return 1}()||(y=[],0)),function(){for(const t of[".rc-imageselect-error-select-more",".rc-imageselect-error-dynamic-more",".rc-imageselect-error-select-something"]){var e=document.querySelector(t);if(""===e?.style.display||0===e?.tabIndex)return 1}}())y=[];else if(await d()){var{task:c,is_hard:r,cells:t,background_url:i,urls:l}=await a(),n=await BG.exec("Settings.get");if(n.enabled&&n.recaptcha_auto_solve){var o=9==t.length?3:4,s=[];let e,a=[];if(null===i){e="1x1";for(let e=0;e<l.length;e++){var u=l[e],m=t[e];u&&!y.includes(u)&&(s.push(u),a.push(m))}}else s.push(i),e=o+"x"+o,a=t;var i=Time.time(),h=(await NopeCHA.post({captcha_type:IS_DEVELOPMENT?"recaptcha_dev":"recaptcha",task:c,image_urls:s,grid:e,key:n.key}))["data"];if(h){c=parseInt(n.recaptcha_solve_delay_time)||1e3,n=n.recaptcha_solve_delay?c-(Time.time()-i):0;0<n&&await Time.sleep(n);let t=0;for(let e=0;e<h.length;e++)!1!==h[e]&&(t++,function(e){try{return e.classList.contains("rc-imageselect-tileselected")}catch{}}(a[e])||a[e]?.click());for(const f of l)y.push(f),9<y.length&&y.shift();(3==o&&r&&0===t&&await d()||3==o&&!r||4==o)&&(await Time.sleep(200),document.querySelector("#recaptcha-verify-button")?.click())}}}}let r=!1,g=!1,y=[];for(;;){await Time.sleep(1e3);var i,l=await BG.exec("Settings.get");l&&l.enabled&&"Image"===l.recaptcha_solve_method&&(i=await Location.hostname(),l.disabled_hosts.includes(i)||(await async function(){var e=[...document.querySelectorAll('iframe[src*="/recaptcha/api2/bframe"]'),...document.querySelectorAll('iframe[src*="/recaptcha/enterprise/bframe"]')];if(0<e.length){for(const t of e)if("visible"===window.getComputedStyle(t).visibility)return BG.exec("Cache.set",{name:"recaptcha_image_visible",value:!0,tab_specific:!0});await BG.exec("Cache.set",{name:"recaptcha_image_visible",value:!1,tab_specific:!0})}}(),await async function(){var e=[...document.querySelectorAll('iframe[src*="/recaptcha/api2/anchor"]'),...document.querySelectorAll('iframe[src*="/recaptcha/enterprise/anchor"]')];if(0<e.length){for(const t of e)if("visible"===window.getComputedStyle(t).visibility)return BG.exec("Cache.set",{name:"recaptcha_widget_visible",value:!0,tab_specific:!0});await BG.exec("Cache.set",{name:"recaptcha_widget_visible",value:!1,tab_specific:!0})}}(),l.recaptcha_auto_open&&null!==document.querySelector(".recaptcha-checkbox")?await t():l.recaptcha_auto_solve&&null!==document.querySelector("#rc-imageselect")&&await c()))}})();

Wyświetl plik

@ -0,0 +1 @@
(async()=>{let i=null,t=!1,n=!1;function s(e){let t=e;for(;t&&!t.classList?.contains("rc-imageselect-tile");)t=t.parentNode;return t}function a(e,t,n=!1){!e||!n&&i===e||(!0===t&&e.classList.contains("rc-imageselect-tileselected")||!1===t&&!e.classList.contains("rc-imageselect-tileselected"))&&e.click()}document.addEventListener("mousedown",e=>{e=s(e?.target);e&&(n=e.classList.contains("rc-imageselect-tileselected")?t=!0:!(t=!0),i=e)}),document.addEventListener("mouseup",e=>{t=!1,i=null}),document.addEventListener("mousemove",e=>{e=s(e?.target);t&&(i!==e&&null!==i&&a(i,n,!0),a(e,n))});window.addEventListener("load",()=>{var e=document.body.appendChild(document.createElement("style")).sheet;e.insertRule(".rc-imageselect-table-33, .rc-imageselect-table-42, .rc-imageselect-table-44 {transition-duration: 0.5s !important}",0),e.insertRule(".rc-imageselect-tile {transition-duration: 2s !important}",1),e.insertRule(".rc-imageselect-dynamic-selected {transition-duration: 1s !important}",2),e.insertRule(".rc-imageselect-progress {transition-duration: 0.5s !important}",3),e.insertRule(".rc-image-tile-overlay {transition-duration: 0.5s !important}",4),e.insertRule("#rc-imageselect img {pointer-events: none !important}",5)})})();

Wyświetl plik

@ -0,0 +1 @@
(async()=>{function e(){var e,t;if(!i())return e="true"===document.querySelector(".recaptcha-checkbox")?.getAttribute("aria-checked"),t=document.querySelector("#recaptcha-verify-button")?.disabled,e||t}function i(){return"Try again later"===document.querySelector(".rc-doscaptcha-header")?.innerText}async function t(){!0!==await BG.exec("Cache.get",{name:"recaptcha_widget_visible",tab_specific:!0})||e()||(await Time.sleep(500),document.querySelector("#recaptcha-anchor")?.click())}async function a(t){var a=await BG.exec("Cache.get",{name:"recaptcha_image_visible",tab_specific:!0});if(!0===a&&!e()&&!i()){a=document.querySelector(".rc-audiochallenge-tdownload-link")?.href,a=(fetch(a),document.querySelector("#audio-source")?.src?.replace("recaptcha.net","google.com"));let e=document.querySelector("html")?.getAttribute("lang")?.trim();e&&0!==e.length||(e="en");var c=Time.time(),a=await Net.fetch("https://engageub.pythonanywhere.com",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:"input="+encodeURIComponent(a)+"&lang="+e});document.querySelector("#audio-response").value=a;a=parseInt(t.recaptcha_solve_delay_time)||1e3,t=t.recaptcha_solve_delay?a-(Time.time()-c):0;0<t&&await Time.sleep(t),document.querySelector("#recaptcha-verify-button")?.click()}}for(;;){await Time.sleep(1e3);var c,r=await BG.exec("Settings.get");r&&r.enabled&&"Speech"===r.recaptcha_solve_method&&(c=await Location.hostname(),r.disabled_hosts.includes(c)||(await async function(){var e=[...document.querySelectorAll('iframe[src*="/recaptcha/api2/bframe"]'),...document.querySelectorAll('iframe[src*="/recaptcha/enterprise/bframe"]')];if(0<e.length){for(const t of e)if("visible"===window.getComputedStyle(t).visibility)return BG.exec("Cache.set",{name:"recaptcha_image_visible",value:!0,tab_specific:!0});await BG.exec("Cache.set",{name:"recaptcha_image_visible",value:!1,tab_specific:!0})}}(),await async function(){var e=[...document.querySelectorAll('iframe[src*="/recaptcha/api2/anchor"]'),...document.querySelectorAll('iframe[src*="/recaptcha/enterprise/anchor"]')];if(0<e.length){for(const t of e)if("visible"===window.getComputedStyle(t).visibility)return BG.exec("Cache.set",{name:"recaptcha_widget_visible",value:!0,tab_specific:!0});await BG.exec("Cache.set",{name:"recaptcha_widget_visible",value:!1,tab_specific:!0})}}(),r.recaptcha_auto_open&&null!==document.querySelector(".recaptcha-checkbox")?await t():r.recaptcha_auto_solve&&null!==document.querySelector(".rc-imageselect-instructions")?await(!0===await BG.exec("Cache.get",{name:"recaptcha_image_visible",tab_specific:!0})&&!e()&&(await Time.sleep(500),!document.querySelector("#recaptcha-audio-button")?.click())):!r.recaptcha_auto_solve||null===document.querySelector("#audio-instructions")&&null===document.querySelector(".rc-doscaptcha-header")||await a(r)))}})();

Wyświetl plik

@ -0,0 +1,3 @@
(async()=>{function e(){try{function t(t){return`<p style='font-family: monospace; font-size: 12px; white-space: pre;'>${t}</p>`}var e=[];for(const n of arguments)e.push(t(n));e.push(t('Join us on <a href="https://nopecha.com/discord" target="_blank">Discord</a>')),document.body.innerHTML=e.join("<hr>")}catch(t){}}try{var t,n;document.location.hash?(e("Importing settings..."),await BG.exec("Settings.get"),t=SettingsManager.import(document.location.hash),await BG.exec("Settings.update",{settings:t}),e(`Visiting this URL will import your NopeCHA settings.
<a href="${n=window.location.href}">${n}</a>`,`Successfully imported settings.
`+JSON.stringify(t,null,4))):e("Invalid URL.\nPlease set the URL hash and reload the page.","Example: https://nopecha.com/setup#TESTKEY123")}catch(t){e("Failed to import settings.\nPlease verify that your URL is formed properly.")}})();

Wyświetl plik

@ -0,0 +1 @@
(async()=>{async function r(e){function c(a){return new Promise(e=>{const t=new Image;t.onload=()=>e(t),t.src=function(e){let t=e.style.backgroundImage;return t&&((e=t.trim().match(/(?!^)".*?"/g))&&0!==e.length||(t=null),t=e[0].replaceAll('"',"")),t}(a)})}try{return(await async function(e){var t=document.querySelector(e);if(t instanceof HTMLCanvasElement)return t;let a;if(a=t instanceof HTMLImageElement?t:await c(t))return(t=document.createElement("canvas")).width=a.naturalWidth,t.height=a.naturalHeight,t.getContext("2d").drawImage(a,0,0),t;throw Error("failed to get image element for "+e)}(e)).toDataURL("image/jpeg").split(";base64,")[1]}catch(e){return null}}let l=null;async function e(){var e,t,a,c,n=(e=500,await new Promise(t=>{let a=!1;const c=setInterval(async()=>{if(!a){a=!0;var e=await BG.exec("Settings.get");if(e.textcaptcha_auto_solve){e=await r(e.textcaptcha_image_selector);if(e&&l!==e)return l=e,clearInterval(c),a=!1,t({image_data:e})}a=!1}},e)}))["image_data"],i=await BG.exec("Settings.get");i.enabled&&i.textcaptcha_auto_solve&&(c=Time.time(),{job_id:t,data:n}=await NopeCHA.post({captcha_type:IS_DEVELOPMENT?"textcaptcha_dev":"textcaptcha",image_data:[n],key:i.key}),n)&&(a=(a=parseInt(i.textcaptcha_solve_delay_time))||100,0<(a=i.textcaptcha_solve_delay?a-(Time.time()-c):0)&&await Time.sleep(a),n)&&0<n.length&&(c=document.querySelector(i.textcaptcha_input_selector))&&!c.value&&(c.value=n[0])}for(;;){await Time.sleep(1e3);var t,a=await BG.exec("Settings.get");a&&a.enabled&&(t=await Location.hostname(),a.disabled_hosts.includes(t)||a.textcaptcha_auto_solve&&function(e){try{var t;return document.querySelector(e.textcaptcha_image_selector)?!(!(t=document.querySelector(e.textcaptcha_input_selector))||t.value):void 0}catch(e){}}(a)&&await e())}})();

Wyświetl plik

@ -0,0 +1,270 @@
'use strict';
/**
* Set to true for the following behavior:
* - Request server to recognize using bleeding-edge models
* - Reload FunCAPTCHA on verification
*/
const IS_DEVELOPMENT = false;
/**
* Trying to be an Enum but javascript doesn't have enums
*/
class RunningAs {
// Background script running on-demand
static BACKGROUND = 'BACKGROUND';
// Popup specified in manifest as "action"
static POPUP = 'POPUP';
// Content script running in page
static CONTENT = 'CONTENT';
// (somehow) Standalone run of script running in webpage
static WEB = 'WEB';
}
Object.freeze(RunningAs);
const runningAt = (() => {
let getBackgroundPage = globalThis?.chrome?.extension?.getBackgroundPage;
if (getBackgroundPage){
return getBackgroundPage() === window ? RunningAs.BACKGROUND : RunningAs.POPUP;
}
return globalThis?.chrome?.runtime?.onMessage ? RunningAs.CONTENT : RunningAs.WEB;
})();
function deep_copy(obj) {
return JSON.parse(JSON.stringify(obj));
}
class Util {
static CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
static pad_left(s, char, n) {
while (`${s}`.length < n) {
s = `${char}${s}`;
}
return s;
}
static capitalize(s) {
return s.charAt(0).toUpperCase() + s.slice(1);
}
static parse_int(s, fallback) {
if (!s) {
s = fallback;
}
return parseInt(s);
}
static parse_bool(s, fallback) {
if (s === 'true') {
s = true;
}
else if (s === 'false') {
s = false;
}
else {
s = fallback;
}
return s;
}
static parse_string(s, fallback) {
if (!s) {
s = fallback;
}
return s;
}
static parse_json(s, fallback) {
if (!s) {
s = fallback;
}
else {
s = JSON.parse(s);
}
return s;
}
static generate_id(n) {
let result = '';
for (let i = 0; i < n; i++) {
result += Util.CHARS.charAt(Math.floor(Math.random() * Util.CHARS.length));
}
return result;
}
}
class Time {
static time() {
if (!Date.now) {
Date.now = () => new Date().getTime();
}
return Date.now();
}
static date() {
return new Date();
}
static sleep(i=1000) {
return new Promise(resolve => setTimeout(resolve, i));
}
static async random_sleep(min, max) {
const duration = Math.floor(Math.random() * (max - min) + min);
return await Time.sleep(duration);
}
static seconds_as_hms(t) {
t = Math.max(0, t);
const hours = Util.pad_left(Math.floor(t / 3600), '0', 2);
t %= 3600;
const minutes = Util.pad_left(Math.floor(t / 60), '0', 2);
const seconds = Util.pad_left(Math.floor(t % 60), '0', 2);
return `${hours}:${minutes}:${seconds}`;
}
static string(d=null) {
if (!d) {
d = Time.date();
}
const month = Util.pad_left(d.getMonth() + 1, '0', 2);
const date = Util.pad_left(d.getDate(), '0', 2);
const year = d.getFullYear();
const hours = Util.pad_left(d.getHours() % 12, '0', 2);
const minutes = Util.pad_left(d.getMinutes(), '0', 2);
const seconds = Util.pad_left(d.getSeconds(), '0', 2);
const period = d.getHours() >= 12 ? 'PM' : 'AM';
return `${month}/${date}/${year} ${hours}:${minutes}:${seconds} ${period}`;
}
}
class SettingsManager {
static DEFAULT = {
version: 15,
key: '',
enabled: true,
disabled_hosts: [],
hcaptcha_auto_open: true,
hcaptcha_auto_solve: true,
hcaptcha_solve_delay: true,
hcaptcha_solve_delay_time: 3000,
recaptcha_auto_open: true,
recaptcha_auto_solve: true,
recaptcha_solve_delay: true,
recaptcha_solve_delay_time: 2000,
recaptcha_solve_method: 'Image',
funcaptcha_auto_open: true,
funcaptcha_auto_solve: true,
funcaptcha_solve_delay: true,
funcaptcha_solve_delay_time: 1000,
awscaptcha_auto_open: true,
awscaptcha_auto_solve: true,
awscaptcha_solve_delay: true,
awscaptcha_solve_delay_time: 1000,
textcaptcha_auto_solve: true,
textcaptcha_solve_delay: true,
textcaptcha_solve_delay_time: 100,
textcaptcha_image_selector: '',
textcaptcha_input_selector: '',
};
static ENCODE_FIELDS = {
enabled: {parse: Util.parse_bool, encode: encodeURIComponent},
disabled_hosts: {parse: Util.parse_json, encode: e => encodeURIComponent(JSON.stringify(e))},
hcaptcha_auto_open: {parse: Util.parse_bool, encode: encodeURIComponent},
hcaptcha_auto_solve: {parse: Util.parse_bool, encode: encodeURIComponent},
hcaptcha_solve_delay: {parse: Util.parse_bool, encode: encodeURIComponent},
hcaptcha_solve_delay_time: {parse: Util.parse_int, encode: encodeURIComponent},
recaptcha_auto_open: {parse: Util.parse_bool, encode: encodeURIComponent},
recaptcha_auto_solve: {parse: Util.parse_bool, encode: encodeURIComponent},
recaptcha_solve_delay: {parse: Util.parse_bool, encode: encodeURIComponent},
recaptcha_solve_delay_time: {parse: Util.parse_int, encode: encodeURIComponent},
recaptcha_solve_method: {parse: Util.parse_string, encode: encodeURIComponent},
funcaptcha_auto_open: {parse: Util.parse_bool, encode: encodeURIComponent},
funcaptcha_auto_solve: {parse: Util.parse_bool, encode: encodeURIComponent},
funcaptcha_solve_delay: {parse: Util.parse_bool, encode: encodeURIComponent},
funcaptcha_solve_delay_time: {parse: Util.parse_int, encode: encodeURIComponent},
awscaptcha_auto_open: {parse: Util.parse_bool, encode: encodeURIComponent},
awscaptcha_auto_solve: {parse: Util.parse_bool, encode: encodeURIComponent},
awscaptcha_solve_delay: {parse: Util.parse_bool, encode: encodeURIComponent},
awscaptcha_solve_delay_time: {parse: Util.parse_int, encode: encodeURIComponent},
textcaptcha_auto_solve: {parse: Util.parse_bool, encode: encodeURIComponent},
textcaptcha_solve_delay: {parse: Util.parse_bool, encode: encodeURIComponent},
textcaptcha_solve_delay_time: {parse: Util.parse_int, encode: encodeURIComponent},
textcaptcha_image_selector: {parse: Util.parse_string, encode: encodeURIComponent},
textcaptcha_input_selector: {parse: Util.parse_string, encode: encodeURIComponent},
};
static IMPORT_URL = 'https://nopecha.com/setup';
static DELIMITER = '|';
static export(settings) {
if (!settings.key) {
return false;
}
const fields = [settings.key];
for (const k in SettingsManager.ENCODE_FIELDS) {
fields.push(`${k}=${SettingsManager.ENCODE_FIELDS[k].encode(settings[k])}`);
}
const encoded_hash = `#${fields.join(SettingsManager.DELIMITER)}`;
return `${SettingsManager.IMPORT_URL}${encoded_hash}`;
}
static import(encoded_hash) {
const settings = {};
// Split by delimiter
const fields = encoded_hash.split(SettingsManager.DELIMITER);
if (fields.length === 0) {
return settings;
}
// Parse key
const key = fields.shift();
if (key.length <= 1) {
console.error('invalid key for settings', key);
return settings;
}
settings.key = key.substring(1);
// Parse additional fields
for (const field of fields) {
const kv = field.split('=');
const k = kv.shift();
const v_raw = kv.join('=');
if (!(k in SettingsManager.ENCODE_FIELDS)) {
console.error('invalid field for settings', field);
continue;
}
const v = decodeURIComponent(v_raw);
console.log('v', v);
settings[k] = SettingsManager.ENCODE_FIELDS[k].parse(v, SettingsManager.DEFAULT[k]);
}
return settings;
}
}

Wyświetl plik

@ -0,0 +1,270 @@
'use strict';
/**
* Set to true for the following behavior:
* - Request server to recognize using bleeding-edge models
* - Reload FunCAPTCHA on verification
*/
export const IS_DEVELOPMENT = false;
/**
* Trying to be an Enum but javascript doesn't have enums
*/
export class RunningAs {
// Background script running on-demand
static BACKGROUND = 'BACKGROUND';
// Popup specified in manifest as "action"
static POPUP = 'POPUP';
// Content script running in page
static CONTENT = 'CONTENT';
// (somehow) Standalone run of script running in webpage
static WEB = 'WEB';
}
Object.freeze(RunningAs);
export const runningAt = (() => {
let getBackgroundPage = globalThis?.chrome?.extension?.getBackgroundPage;
if (getBackgroundPage){
return getBackgroundPage() === window ? RunningAs.BACKGROUND : RunningAs.POPUP;
}
return globalThis?.chrome?.runtime?.onMessage ? RunningAs.CONTENT : RunningAs.WEB;
})();
export function deep_copy(obj) {
return JSON.parse(JSON.stringify(obj));
}
export class Util {
static CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
static pad_left(s, char, n) {
while (`${s}`.length < n) {
s = `${char}${s}`;
}
return s;
}
static capitalize(s) {
return s.charAt(0).toUpperCase() + s.slice(1);
}
static parse_int(s, fallback) {
if (!s) {
s = fallback;
}
return parseInt(s);
}
static parse_bool(s, fallback) {
if (s === 'true') {
s = true;
}
else if (s === 'false') {
s = false;
}
else {
s = fallback;
}
return s;
}
static parse_string(s, fallback) {
if (!s) {
s = fallback;
}
return s;
}
static parse_json(s, fallback) {
if (!s) {
s = fallback;
}
else {
s = JSON.parse(s);
}
return s;
}
static generate_id(n) {
let result = '';
for (let i = 0; i < n; i++) {
result += Util.CHARS.charAt(Math.floor(Math.random() * Util.CHARS.length));
}
return result;
}
}
export class Time {
static time() {
if (!Date.now) {
Date.now = () => new Date().getTime();
}
return Date.now();
}
static date() {
return new Date();
}
static sleep(i=1000) {
return new Promise(resolve => setTimeout(resolve, i));
}
static async random_sleep(min, max) {
const duration = Math.floor(Math.random() * (max - min) + min);
return await Time.sleep(duration);
}
static seconds_as_hms(t) {
t = Math.max(0, t);
const hours = Util.pad_left(Math.floor(t / 3600), '0', 2);
t %= 3600;
const minutes = Util.pad_left(Math.floor(t / 60), '0', 2);
const seconds = Util.pad_left(Math.floor(t % 60), '0', 2);
return `${hours}:${minutes}:${seconds}`;
}
static string(d=null) {
if (!d) {
d = Time.date();
}
const month = Util.pad_left(d.getMonth() + 1, '0', 2);
const date = Util.pad_left(d.getDate(), '0', 2);
const year = d.getFullYear();
const hours = Util.pad_left(d.getHours() % 12, '0', 2);
const minutes = Util.pad_left(d.getMinutes(), '0', 2);
const seconds = Util.pad_left(d.getSeconds(), '0', 2);
const period = d.getHours() >= 12 ? 'PM' : 'AM';
return `${month}/${date}/${year} ${hours}:${minutes}:${seconds} ${period}`;
}
}
export class SettingsManager {
static DEFAULT = {
version: 15,
key: '',
enabled: true,
disabled_hosts: [],
hcaptcha_auto_open: true,
hcaptcha_auto_solve: true,
hcaptcha_solve_delay: true,
hcaptcha_solve_delay_time: 3000,
recaptcha_auto_open: true,
recaptcha_auto_solve: true,
recaptcha_solve_delay: true,
recaptcha_solve_delay_time: 2000,
recaptcha_solve_method: 'Image',
funcaptcha_auto_open: true,
funcaptcha_auto_solve: true,
funcaptcha_solve_delay: true,
funcaptcha_solve_delay_time: 1000,
awscaptcha_auto_open: true,
awscaptcha_auto_solve: true,
awscaptcha_solve_delay: true,
awscaptcha_solve_delay_time: 1000,
textcaptcha_auto_solve: true,
textcaptcha_solve_delay: true,
textcaptcha_solve_delay_time: 100,
textcaptcha_image_selector: '',
textcaptcha_input_selector: '',
};
static ENCODE_FIELDS = {
enabled: {parse: Util.parse_bool, encode: encodeURIComponent},
disabled_hosts: {parse: Util.parse_json, encode: e => encodeURIComponent(JSON.stringify(e))},
hcaptcha_auto_open: {parse: Util.parse_bool, encode: encodeURIComponent},
hcaptcha_auto_solve: {parse: Util.parse_bool, encode: encodeURIComponent},
hcaptcha_solve_delay: {parse: Util.parse_bool, encode: encodeURIComponent},
hcaptcha_solve_delay_time: {parse: Util.parse_int, encode: encodeURIComponent},
recaptcha_auto_open: {parse: Util.parse_bool, encode: encodeURIComponent},
recaptcha_auto_solve: {parse: Util.parse_bool, encode: encodeURIComponent},
recaptcha_solve_delay: {parse: Util.parse_bool, encode: encodeURIComponent},
recaptcha_solve_delay_time: {parse: Util.parse_int, encode: encodeURIComponent},
recaptcha_solve_method: {parse: Util.parse_string, encode: encodeURIComponent},
funcaptcha_auto_open: {parse: Util.parse_bool, encode: encodeURIComponent},
funcaptcha_auto_solve: {parse: Util.parse_bool, encode: encodeURIComponent},
funcaptcha_solve_delay: {parse: Util.parse_bool, encode: encodeURIComponent},
funcaptcha_solve_delay_time: {parse: Util.parse_int, encode: encodeURIComponent},
awscaptcha_auto_open: {parse: Util.parse_bool, encode: encodeURIComponent},
awscaptcha_auto_solve: {parse: Util.parse_bool, encode: encodeURIComponent},
awscaptcha_solve_delay: {parse: Util.parse_bool, encode: encodeURIComponent},
awscaptcha_solve_delay_time: {parse: Util.parse_int, encode: encodeURIComponent},
textcaptcha_auto_solve: {parse: Util.parse_bool, encode: encodeURIComponent},
textcaptcha_solve_delay: {parse: Util.parse_bool, encode: encodeURIComponent},
textcaptcha_solve_delay_time: {parse: Util.parse_int, encode: encodeURIComponent},
textcaptcha_image_selector: {parse: Util.parse_string, encode: encodeURIComponent},
textcaptcha_input_selector: {parse: Util.parse_string, encode: encodeURIComponent},
};
static IMPORT_URL = 'https://nopecha.com/setup';
static DELIMITER = '|';
static export(settings) {
if (!settings.key) {
return false;
}
const fields = [settings.key];
for (const k in SettingsManager.ENCODE_FIELDS) {
fields.push(`${k}=${SettingsManager.ENCODE_FIELDS[k].encode(settings[k])}`);
}
const encoded_hash = `#${fields.join(SettingsManager.DELIMITER)}`;
return `${SettingsManager.IMPORT_URL}${encoded_hash}`;
}
static import(encoded_hash) {
const settings = {};
// Split by delimiter
const fields = encoded_hash.split(SettingsManager.DELIMITER);
if (fields.length === 0) {
return settings;
}
// Parse key
const key = fields.shift();
if (key.length <= 1) {
console.error('invalid key for settings', key);
return settings;
}
settings.key = key.substring(1);
// Parse additional fields
for (const field of fields) {
const kv = field.split('=');
const k = kv.shift();
const v_raw = kv.join('=');
if (!(k in SettingsManager.ENCODE_FIELDS)) {
console.error('invalid field for settings', field);
continue;
}
const v = decodeURIComponent(v_raw);
console.log('v', v);
settings[k] = SettingsManager.ENCODE_FIELDS[k].parse(v, SettingsManager.DEFAULT[k]);
}
return settings;
}
}