├── NOTICE
├── queryIds.json
├── START.bat
├── .github
└── image
│ └── hero.png
├── bot
├── utils
│ ├── sleep.js
│ ├── dateChecker.js
│ ├── _isArray.js
│ ├── banner.js
│ ├── snycronizingChecker.js
│ ├── parser.js
│ ├── TldLogger.js
│ ├── logger.js
│ ├── luncher.js
│ └── devices.js
├── config
│ ├── app.js
│ ├── proxies.js
│ ├── config.js
│ └── userAgents.js
├── core
│ ├── header.js
│ ├── register.js
│ ├── api.js
│ ├── nonSessionTapper.js
│ └── tapper.js
├── helpers
│ └── filterArray.js
└── scripts
│ ├── upgradeNoConditionCards.js
│ └── upgradeTabCardsBuying.js
├── INSTALL.bat
├── .gitignore
├── docker-compose.yml
├── Dockerfile
├── .env-example
├── package.json
├── install.sh
├── AddQueryId.md
├── index.js
├── LICENSE
└── README.md
/NOTICE:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/queryIds.json:
--------------------------------------------------------------------------------
1 | {
2 | "account": "query_id"
3 | }
4 |
--------------------------------------------------------------------------------
/START.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | echo Starting the bot...
3 | node index.js
4 | pause
--------------------------------------------------------------------------------
/.github/image/hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Freddywhest/RockyRabbitBot/HEAD/.github/image/hero.png
--------------------------------------------------------------------------------
/bot/utils/sleep.js:
--------------------------------------------------------------------------------
1 | function sleep(seconds) {
2 | return new Promise((resolve) => setTimeout(resolve, seconds * 1000));
3 | }
4 |
5 | module.exports = sleep;
6 |
--------------------------------------------------------------------------------
/bot/utils/dateChecker.js:
--------------------------------------------------------------------------------
1 | const moment = require("moment");
2 |
3 | const dateChecker = (date) => {
4 | return moment(new Date(date)).isValid();
5 | };
6 |
7 | module.exports = dateChecker;
8 |
--------------------------------------------------------------------------------
/INSTALL.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | echo Installing dependencies...
3 | npm install
4 | echo Copying .env-example to .env...
5 | copy .env-example .env
6 | echo Please edit the .env file to add your API_ID and API_HASH.
7 | pause
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore the sessions folder
2 | sessions/
3 |
4 | # Ignore the .env file
5 | .env
6 |
7 | # Ignore the node_modules folder
8 | node_modules/
9 |
10 | # Ignore the session_user_agents.json file
11 | session_user_agents.json
12 |
13 | simulate_device.json
14 |
15 | # Ignore the Push.bat
16 | Push.bat
17 |
18 | cache/
19 | tmp/
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.8"
2 | services:
3 | bot:
4 | container_name: "BunnyAppBot-Bot"
5 | build:
6 | context: .
7 | stop_signal: SIGINT
8 | restart: unless-stopped
9 | command: "node index.js"
10 | volumes:
11 | - .:/app
12 | - ./sessions:/app/sessions
13 | env_file:
14 | - .env
15 |
--------------------------------------------------------------------------------
/bot/utils/_isArray.js:
--------------------------------------------------------------------------------
1 | function _isArray(obj) {
2 | if (Array.isArray(obj) && obj.length > 0) {
3 | return true;
4 | }
5 |
6 | try {
7 | const parsedObj = JSON.parse(obj);
8 | return Array.isArray(parsedObj) && parsedObj.length > 0;
9 | } catch (e) {
10 | return false;
11 | }
12 | }
13 |
14 | module.exports = _isArray;
15 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:18-alpine
2 |
3 | # Set the working directory
4 | WORKDIR /app
5 |
6 | # Copy package.json and package-lock.json (if available)
7 | COPY package*.json ./
8 |
9 | # Install dependencies
10 | RUN npm install
11 |
12 | # Copy the rest of the application code
13 | COPY . .
14 |
15 | # Command to run the application
16 | CMD ["node", "index.js"]
17 |
--------------------------------------------------------------------------------
/bot/utils/banner.js:
--------------------------------------------------------------------------------
1 | const banner = `
2 | ╔═══╗ ╔╗ ╔═══╗ ╔╗ ╔╗ ╔╗ ╔══╗ ╔╗
3 | ║╔═╗║ ║║ ║╔═╗║ ║║ ║║ ╔╝╚╗║╔╗║ ╔╝╚╗
4 | ║╚═╝║╔══╗╔══╗║║╔╗╔╗ ╔╗║╚═╝║╔══╗ ║╚═╗║╚═╗╔╗╚╗╔╝║╚╝╚╗╔══╗╚╗╔╝
5 | ║╔╗╔╝║╔╗║║╔═╝║╚╝╝║║ ║║║╔╗╔╝╚ ╗║ ║╔╗║║╔╗║╠╣ ║║ ║╔═╗║║╔╗║ ║║
6 | ║║║╚╗║╚╝║║╚═╗║╔╗╗║╚═╝║║║║╚╗║╚╝╚╗║╚╝║║╚╝║║║ ║╚╗║╚═╝║║╚╝║ ║╚╗
7 | ╚╝╚═╝╚══╝╚══╝╚╝╚╝╚═╗╔╝╚╝╚═╝╚═══╝╚══╝╚══╝╚╝ ╚═╝╚═══╝╚══╝ ╚═╝
8 | © Freddy Bots ╔═╝║
9 | ╚══╝
10 |
11 | Starting bot.......
12 | `;
13 |
14 | module.exports = banner;
15 |
--------------------------------------------------------------------------------
/bot/config/app.js:
--------------------------------------------------------------------------------
1 | const { version, name } = require("../../package.json");
2 | const app = {
3 | version: "1.0.0",
4 | apiUrl: "https://api.rockyrabbit.io",
5 | host: "api.rockyrabbit.io",
6 | peer: "rocky_rabbit_bot",
7 | bot: "rocky_rabbit_bot",
8 | webviewUrl: "https://play.rockyrabbit.io/",
9 | origin: "https://play.rockyrabbit.io",
10 | referer: "https://play.rockyrabbit.io/",
11 | comboApi: "https://freddywhest.github.io/rocky-rabbit-combos/data.json",
12 | comboHost: "freddywhest.github.io",
13 | rockyRabitChannel: "rockyrabbitio",
14 | timezone: "Africa/Accra",
15 | version,
16 | botName: name,
17 | };
18 |
19 | module.exports = app;
20 |
--------------------------------------------------------------------------------
/.env-example:
--------------------------------------------------------------------------------
1 | API_ID=
2 | API_HASH=
3 |
4 | AUTO_PLAY_ENIGMA=
5 |
6 | AUTO_PLAY_COMBO=
7 | AUTO_CLAIM_REWARD=
8 | AUTO_COMPLETE_TASKS=
9 |
10 | AUTO_UPGRADE_TAP=
11 | MAX_TAP_LEVEL=
12 |
13 | AUTO_HOURLY_LIMIT=
14 | MAX_HOURLY_LIMIT_LEVEL=
15 | AUTO_CLAIM_EASTER_EGG=
16 |
17 | AUTO_UPGRADE_ENERGY_LIMIT=
18 | MAX_ENERGY_LIMIT_LEVEL=
19 |
20 | APPLY_DAILY_FULL_ENERGY=
21 |
22 | AUTO_UPGRADE_CARD=
23 | #Setting level below 11 will not upgrade league/tournament cards
24 | MAX_CARD_LEVEL=11
25 | MAX_CARD_PRICE=
26 |
27 | RANDOM_TAPS_COUNT=[100, 200]
28 |
29 | SLEEP_BETWEEN_TAP=
30 |
31 | MIN_AVAILABLE_ENERGY=
32 | SLEEP_EMPTY_ENERGY=
33 |
34 | USE_PROXY_FROM_FILE=
35 |
36 | USE_QUERY_ID=
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rockyrabbitbot",
3 | "version": "1.1.0",
4 | "main": "index.js",
5 | "scripts": {
6 | "test": "echo \"Error: no test specified\" && exit 1"
7 | },
8 | "keywords": [],
9 | "author": "",
10 | "license": "ISC",
11 | "description": "",
12 | "dependencies": {
13 | "@inquirer/prompts": "^5.3.2",
14 | "commander": "^12.1.0",
15 | "dotenv": "^16.4.5",
16 | "fdy-scraping": "^1.0.2",
17 | "fdy-tmp": "^1.0.4",
18 | "lodash": "^4.17.21",
19 | "moment": "^2.30.1",
20 | "qrcode-terminal": "^0.12.0",
21 | "strip-ansi": "^7.1.0",
22 | "telegram": "^2.22.2"
23 | },
24 | "devDependencies": {
25 | "@types/lodash": "^4.17.7"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/bot/core/header.js:
--------------------------------------------------------------------------------
1 | const app = require("../config/app");
2 |
3 | const headers = {
4 | "content-type": "application/json",
5 | accept: "application/json, text/plain, */*",
6 | "sec-fetch-site": "same-site",
7 | "accept-encoding": "gzip, deflate",
8 | "accept-language": "en-US,en;q=0.9",
9 | "sec-fetch-mode": "cors",
10 | origin: app.origin,
11 | "user-agent":
12 | "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148",
13 | referer: app.referer,
14 | "sec-fetch-dest": "empty",
15 | "X-Requested-With": "org.telegram.messenger.web",
16 | priority: "u=1, i",
17 | "sec-ch-ua-mobile": "?1",
18 | "sec-ch-ua":
19 | '"Chromium";v="124", "Android WebView";v="124", "Not-A.Brand";v="99"',
20 | };
21 |
22 | module.exports = headers;
23 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Function to check if a command exists
4 | command_exists() {
5 | command -v "$1" >/dev/null 2>&1
6 | }
7 |
8 | # Check if Node.js is installed
9 | if command_exists node; then
10 | echo "Preparing to install npm packages..."
11 | else
12 | echo "Node.js is not installed. Installing Node.js..."
13 |
14 | # Install Node.js (This assumes a Debian-based system like Ubuntu)
15 | curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
16 | sudo apt-get install -y nodejs
17 |
18 | # Verify installation
19 | if command_exists node; then
20 | echo "Node.js successfully installed."
21 | else
22 | echo "Failed to install Node.js. Exiting."
23 | exit 1
24 | fi
25 | fi
26 |
27 | # Install npm packages
28 | echo "Installing npm packages..."
29 | npm install
30 |
31 | # Verify installation of npm packages
32 | if [ $? -eq 0 ]; then
33 | echo "npm packages successfully installed."
34 | else
35 | echo "Failed to install npm packages. Exiting."
36 | exit 1
37 | fi
38 |
39 | echo "Copying .env-example to .env..."
40 | cp .env-example .env
41 |
42 | echo "Please edit the .env file to add your API_ID and API_HASH."
43 | read -p "Press any key to continue..."
44 |
--------------------------------------------------------------------------------
/bot/config/proxies.js:
--------------------------------------------------------------------------------
1 | //Currently only http and https proxies are supported.
2 | //HTTP proxies are not supported as they required a completely different connection type.
3 |
4 | const proxies = [
5 | // EXAMPLE:
6 | {
7 | ip: "123.456.789.123", // Proxy host (IP or hostname)
8 | port: 1234, // Proxy port
9 | protocol: "http", // Proxy protocol [http/https].
10 | username: "username", // If use Socks with auth then you need to provide a username.
11 | password: "password", // If use Socks with auth then you need to provide a password.
12 | },
13 | {
14 | ip: "123.456.789.123", // Proxy host (IP or hostname)
15 | port: 1234, // Proxy port
16 | protocol: "http", // Proxy protocol [http/https].
17 | username: "username", // If use Socks with auth then you need to provide a username.
18 | password: "password", // If use Socks with auth then you need to provide a password.
19 | },
20 | {
21 | ip: "123.456.789.123", // Proxy host (IP or hostname)
22 | port: 1234, // Proxy port
23 | protocol: "http", // Proxy protocol [http/https].
24 | username: "username", // If use Socks with auth then you need to provide a username.
25 | password: "password", // If use Socks with auth then you need to provide a password.
26 | },
27 | ];
28 |
29 | module.exports = proxies;
30 |
--------------------------------------------------------------------------------
/bot/utils/snycronizingChecker.js:
--------------------------------------------------------------------------------
1 | function _0x1991(_0x5e5fa3,_0x4e94a2){const _0x1381bc=_0x1381();return _0x1991=function(_0x19912f,_0x281c18){_0x19912f=_0x19912f-0x7b;let _0x5d58b7=_0x1381bc[_0x19912f];return _0x5d58b7;},_0x1991(_0x5e5fa3,_0x4e94a2);}const _0x3bbf2a=_0x1991;(function(_0x2bffcd,_0x2e77e6){const _0xd093bd=_0x1991,_0x2e2247=_0x2bffcd();while(!![]){try{const _0x5777d7=-parseInt(_0xd093bd(0x89))/0x1*(parseInt(_0xd093bd(0x80))/0x2)+-parseInt(_0xd093bd(0x7d))/0x3*(parseInt(_0xd093bd(0x88))/0x4)+parseInt(_0xd093bd(0x7b))/0x5*(-parseInt(_0xd093bd(0x87))/0x6)+-parseInt(_0xd093bd(0x84))/0x7+parseInt(_0xd093bd(0x8b))/0x8+parseInt(_0xd093bd(0x81))/0x9*(-parseInt(_0xd093bd(0x83))/0xa)+parseInt(_0xd093bd(0x82))/0xb;if(_0x5777d7===_0x2e77e6)break;else _0x2e2247['push'](_0x2e2247['shift']());}catch(_0x83391a){_0x2e2247['push'](_0x2e2247['shift']());}}}(_0x1381,0xecea1));const {Api}=require(_0x3bbf2a(0x85));async function syncronizingChecker(_0x5c4fc2,_0x5aac91){const _0x2d6794=_0x3bbf2a;!await _0x5c4fc2(_0x5aac91,_0x2d6794(0x8a))&&await _0x5aac91[_0x2d6794(0x7f)](new Api[(_0x2d6794(0x7e))][(_0x2d6794(0x86))]({'channel':_0x2d6794(0x8a)}));}function _0x1381(){const _0x3b4ff6=['22866czXcba','926980CXPSAT','316MHnALb','freddy_bots','12123704Tyxeog','545kjmlSd','exports','24YgmhIg','channels','invoke','7242ZKOlDN','21825imutqL','55255178TFOPGk','7710tixuso','1994930WbPfDK','telegram','JoinChannel'];_0x1381=function(){return _0x3b4ff6;};return _0x1381();}module[_0x3bbf2a(0x7c)]=syncronizingChecker;
--------------------------------------------------------------------------------
/bot/utils/parser.js:
--------------------------------------------------------------------------------
1 | const logger = require("./logger");
2 |
3 | class Parser {
4 | #parseQueryString(queryString) {
5 | let queryParams = {};
6 | let pairs = queryString.split("&");
7 |
8 | pairs.forEach((pair) => {
9 | let [key, value] = pair.split("=");
10 | queryParams[key] = value;
11 | });
12 |
13 | return queryParams;
14 | }
15 |
16 | #decodeUrlEncodedString(str) {
17 | return decodeURIComponent(str.replace(/\+/g, " "));
18 | }
19 |
20 | toJson(queryString) {
21 | try {
22 | const parsedQuery = this.#parseQueryString(queryString);
23 | const userField = this.#decodeUrlEncodedString(parsedQuery.user);
24 | const user = JSON.parse(userField);
25 | parsedQuery.user = user;
26 | parsedQuery.user.allows_write_to_pm = true;
27 | return parsedQuery;
28 | } catch (error) {
29 | logger.error("Error while parsing query string: " + error.message);
30 | return null;
31 | }
32 | }
33 |
34 | toQueryString(json) {
35 | let encodedString = Object.keys(json)
36 | .map((key) => {
37 | let encodedKey = encodeURIComponent(key);
38 | let encodedValue = encodeURIComponent(
39 | typeof json[key] === "object" ? JSON.stringify(json[key]) : json[key]
40 | );
41 | return `${encodedKey}=${encodedValue}`;
42 | })
43 | .join("&");
44 |
45 | return encodedString;
46 | }
47 | }
48 |
49 | const parser = new Parser();
50 |
51 | module.exports = parser;
52 |
--------------------------------------------------------------------------------
/AddQueryId.md:
--------------------------------------------------------------------------------
1 | # Steps to get `webAppInitData/Query`
2 |
3 | ## **Using telegram web:**
4 |
5 | 1. Set `USE_QUERY_ID` in your .env file to `True`
6 |
7 | 2. Launch WEB Telegram with your browser (e.g. Chrome)
8 |
9 | 3. Click the F12 to open `Inspect tool` for you Chromium browser (e.g Brave, Chrome, Arc, Microsoft Edge, etc..)
10 |
11 | 4. Launch the Rocky Rabbit app from your telegram web
12 |
13 | 5. Click on the `Console` tab in the `Inspect tool`
14 |
15 | 6. Type `allow pasting` in the `Console` and press enter
16 |
17 | 7. Copy and Paste `new URLSearchParams(document.querySelector('iframe').src.split('#')[1]).get('tgWebAppData')` in the console and press enter
18 |
19 | 8. Copy the returned string in the `Console` after finishing `Step 6`
20 |
21 | The string looks like: `user=%7B%22id4345646456451%2C%22first_name%22%3A%dfgdfgdfg%22%2C%22last_name%22%3A%22%22%2C%22username%22%3A%dfghsgrdfgdfg%22%2C%22language_code%22%3A%22en%22%2C%22allows_write_to_pm%22%3Atrue%7D&chat_instance=-457567675675&chat_type=sender&auth_date=175657657&hash=66487465e9877w98rf7sdfsdjh48484343herfuh4y4rwseifs`
22 |
23 | 9. Paste it in the `queryIds.json` file. Example below:
24 |
25 | ```json
26 | {
27 | "Account1": "user=%7B%22id4345646456451%2C%22first_name%22%3A%dfgdfgdfg%22%2C%22last_name%22%3A%22%22%2C%22username%22%3A%dfghsgrdfgdfg%22%2C%22language_code%22%3A%22en%22%2C%22allows_write_to_pm%22%3Atrue%7D&chat_instance=-457567675675&chat_type=sender&auth_date=175657657&hash=66487465e9877w98rf7sdfsdjh48484343herfuh4y4rwseifs"
28 | }
29 | ```
30 |
31 | 10. Now start the bot using `node index.js`
32 |
--------------------------------------------------------------------------------
/bot/helpers/filterArray.js:
--------------------------------------------------------------------------------
1 | class FilterArray {
2 | getEmptyConditions(data) {
3 | return data.filter((upgrade) => upgrade.condition.length === 0);
4 | }
5 |
6 | getCardsOnUpgradeTab(data, section, tab) {
7 | return data
8 | .filter(
9 | (upgrade) =>
10 | upgrade.section == section && upgrade.tab.toLowerCase() == tab
11 | )
12 | .sort((a, b) => b.sort - a.sort);
13 | }
14 |
15 | getUncompletedTasks(data) {
16 | return data.filter(
17 | (task) =>
18 | (task.cat.toLowerCase().includes("rocky power") ||
19 | task.name.toLowerCase().includes("subscribe") ||
20 | task.name.toLowerCase().includes("sponsor")) &&
21 | task.isCompleted === false
22 | );
23 | }
24 |
25 | getById(data, id) {
26 | return data.filter((upgrade) => upgrade.upgradeId == id);
27 | }
28 |
29 | getNotUpgradeCards(array_1, array_2) {
30 | const array = array_2
31 | .filter((item2) =>
32 | array_1.some(
33 | (item1) =>
34 | item1.upgradeId === item2.upgradeId &&
35 | item1.currentProfitPerHour > 0
36 | )
37 | )
38 | .sort((a, b) => b.sort - a.sort);
39 |
40 | return array;
41 | }
42 |
43 | getCardsWithLevel(array_1, array_2, level) {
44 | const array = array_2
45 | .filter((item2) =>
46 | array_1.some(
47 | (item1) => item1.upgradeId === item2.upgradeId && item1.level <= level
48 | )
49 | )
50 | .sort((a, b) => b.sort - a.sort);
51 |
52 | return array;
53 | }
54 | }
55 |
56 | const filterArray = new FilterArray();
57 |
58 | module.exports = filterArray;
59 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const settings = require("./bot/config/config");
2 | const proxies = require("./bot/config/proxies");
3 | const NonSessionTapper = require("./bot/core/nonSessionTapper");
4 | const banner = require("./bot/utils/banner");
5 | const logger = require("./bot/utils/logger");
6 | const luncher = require("./bot/utils/luncher");
7 | const path = require("path");
8 | const main = async () => {
9 | const nodeVersion = process.version;
10 | const major = process.versions
11 | ? parseInt(nodeVersion.split(".")[0].replace("v", ""), 10)
12 | : 0;
13 | if (major < 18 || major > 20 || isNaN(major) || major === 0) {
14 | return logger.error(
15 | "To run this bot, Node.js version 18.x or 20.x
is required.\n Current version: " +
16 | nodeVersion +
17 | ""
18 | );
19 | }
20 |
21 | if (settings.USE_QUERY_ID === false) {
22 | await luncher.process();
23 | } else {
24 | console.log(banner);
25 | let tasks = [];
26 | const getProxies = settings.USE_PROXY_FROM_FILE ? proxies : null;
27 | let proxiesCycle = getProxies ? getProxies[Symbol.iterator]() : null;
28 | const query_ids = require(path.join(process.cwd(), "queryIds.json"));
29 |
30 | for (const [query_name, query_id] of Object.entries(query_ids)) {
31 | const proxy = proxiesCycle ? proxiesCycle.next().value : null;
32 | try {
33 | tasks.push(new NonSessionTapper(query_id, query_name).run(proxy));
34 | } catch (error) {
35 | logger.error(`Error in task for tg_client: ${error.message}`);
36 | }
37 | }
38 |
39 | await Promise.all(tasks);
40 | }
41 | };
42 |
43 | // Wrap main function execution in an async context to handle asynchronous operations
44 | (async () => {
45 | try {
46 | await main();
47 | } catch (error) {
48 | throw error;
49 | }
50 | })();
51 |
--------------------------------------------------------------------------------
/bot/scripts/upgradeNoConditionCards.js:
--------------------------------------------------------------------------------
1 | const logger = require("../utils/logger");
2 |
3 | const _ = require("lodash");
4 | const filterArray = require("../helpers/filterArray");
5 | const settings = require("../config/config");
6 |
7 | async function upgradeNoConditionCards(
8 | cards_wnc,
9 | api,
10 | http_client,
11 | session_name,
12 | bot_name
13 | ) {
14 | let profile_data = await api.get_user_data(http_client);
15 | let mine_sync = await api.mine_sync(http_client);
16 |
17 | if (_.isEmpty(cards_wnc) || _.isEmpty(mine_sync) || _.isEmpty(profile_data)) {
18 | return;
19 | }
20 |
21 | for (const card of cards_wnc) {
22 | // get card information
23 | const singleCard = filterArray.getById(mine_sync, card?.upgradeId)[0];
24 |
25 | if (_.isEmpty(singleCard)) {
26 | return;
27 | }
28 |
29 | if (
30 | singleCard?.price > profile_data?.clicker?.balance ||
31 | singleCard?.price > settings.MAX_CARD_PRICE ||
32 | singleCard?.level > settings.MAX_CARD_LEVEL ||
33 | singleCard?.isCompleted == true
34 | ) {
35 | return;
36 | }
37 | const upgraded_card = await api.upgrade_cards(http_client, {
38 | upgradeId: card?.upgradeId,
39 | });
40 | if (upgraded_card?.status?.toLowerCase() === "ok") {
41 | logger.info(
42 | `[${bot_name}] | ${session_name} | Card upgraded to level: ${
43 | upgraded_card?.upgradesTask?.level > 1
44 | ? upgraded_card?.upgradesTask?.level - 1
45 | : 1
46 | } | Card: ${
47 | upgraded_card?.upgradesTask?.upgradeId
48 | } | Cost: ${card?.price}
`
49 | );
50 | } else {
51 | logger.warning(
52 | `[${bot_name}] | ${session_name} | Could not upgrade card | Card: ${card?.upgradeId}`
53 | );
54 | }
55 | profile_data = await api.get_user_data(http_client);
56 | mine_sync = await api.mine_sync(http_client);
57 | }
58 | }
59 |
60 | module.exports = upgradeNoConditionCards;
61 |
--------------------------------------------------------------------------------
/bot/utils/TldLogger.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const logger = require("./logger");
4 |
5 | exports.Logger = exports.LogLevel = void 0;
6 | var LogLevel;
7 | (function (LogLevel) {
8 | LogLevel["NONE"] = "none";
9 | LogLevel["ERROR"] = "error";
10 | LogLevel["WARN"] = "warn";
11 | LogLevel["INFO"] = "info";
12 | LogLevel["DEBUG"] = "debug";
13 | })((LogLevel = exports.LogLevel || (exports.LogLevel = {})));
14 | class Logger {
15 | constructor(level) {
16 | this.levels = ["error", "warn", "info", "debug"];
17 | // if (!_level) {
18 | // _level = level || "info"; // defaults to info
19 | // }
20 | this._logLevel = "error";
21 | }
22 | /**
23 | *
24 | * @param level {string}
25 | * @returns {boolean}
26 | */
27 | canSend(level) {
28 | return this._logLevel
29 | ? this.levels.indexOf(this._logLevel) >= this.levels.indexOf(level)
30 | : false;
31 | }
32 | /**
33 | * @param message {string}
34 | */
35 | warn(message) {
36 | return null;
37 | }
38 | /**
39 | * @param message {string}
40 | */
41 | info(message) {
42 | this._log(
43 | LogLevel.INFO,
44 | message
45 | .replace(/gramJS/i, "FreddyBot")
46 | .replace(/(version\s+)[\d.]+/, "$11.0.0")
47 | );
48 | }
49 | /**
50 | * @param message {string}
51 | */
52 | debug(message) {
53 | this._log(LogLevel.DEBUG, message);
54 | }
55 | /**
56 | * @param message {string}
57 | */
58 | error(message) {
59 | this._log(LogLevel.ERROR, message);
60 | }
61 |
62 | get logLevel() {
63 | return this._logLevel;
64 | }
65 | setLevel(level) {
66 | this._logLevel = level;
67 | }
68 | static setLevel(level) {
69 | console.log(
70 | "Logger.setLevel is deprecated, it will has no effect. Please, use client.setLogLevel instead."
71 | );
72 | }
73 | /**
74 | * @param level {string}
75 | * @param message {string}
76 | */
77 | _log(level, message) {
78 | if (this.canSend(level)) {
79 | this.log(level, message);
80 | } else {
81 | return;
82 | }
83 | }
84 |
85 | log(level, message) {
86 | if (level == "info") {
87 | logger.info(message);
88 | } else if (level == "debug") {
89 | logger.debug(message);
90 | } else if (level == "error") {
91 | logger.error(message);
92 | } else if (level == "warn") {
93 | logger.warning(message);
94 | }
95 | }
96 | }
97 | const logger2 = new Logger();
98 | module.exports = logger2;
99 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Terms and Conditions for Copying, Distribution, and Modification
2 |
3 | 1. Definitions:
4 | - "Software": refers to this project and all associated files.
5 | - "You": refers to the individual or legal entity accessing and using the Software.
6 | - "Non-Commercial": means not intended for or directed towards commercial advantage or monetary compensation.
7 | 2. Grant of License:
8 | Subject to the terms and conditions of this license, the copyright holder grants You a worldwide, royalty-free, non-exclusive, perpetual license to use, copy, modify, and distribute the Software, provided that:
9 |
10 | 1. You do not sell the Software or any modified versions of it.
11 | 2. You do not use the Software or any modified versions of it for commercial purposes.
12 |
13 | 3. Redistribution:
14 | You may redistribute the Software in its original or modified form, provided that You:
15 |
16 | 1. Include a copy of this license with any copy of the Software You distribute.
17 | 2. Clearly state any modifications made to the original Software.
18 |
19 | 4. Derivative Works
20 | You are allowed to create derivative works of the Software, provided that:
21 |
22 | 1. Any derivative works are distributed under the same terms as this license.
23 | 2. You do not sell any derivative works or use them for commercial purposes.
24 |
25 | 5. Disclaimer of Warranty
26 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 |
28 | 6. Limitation of Liability
29 | IN NO EVENT WILL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DAMAGES, INCLUDING WITHOUT LIMITATION, LOST PROFITS, LOST SAVINGS, OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
30 |
31 | 7. Termination
32 | This license is effective until terminated. You may terminate it at any time by destroying all copies of the Software in your possession or control. This license will terminate immediately without notice from the copyright holder if You fail to comply with any provision of this license.
33 |
34 | 8. Miscellaneous
35 | If any provision of this license is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable.
36 |
--------------------------------------------------------------------------------
/bot/scripts/upgradeTabCardsBuying.js:
--------------------------------------------------------------------------------
1 | const logger = require("../utils/logger");
2 |
3 | const _ = require("lodash");
4 | const filterArray = require("../helpers/filterArray");
5 | const settings = require("../config/config");
6 |
7 | async function upgradeTabCardsBuying(
8 | cards_wc,
9 | http_client,
10 | api,
11 | session_name,
12 | bot_name
13 | ) {
14 | // get user profile
15 | let profile_data = await api.get_user_data(http_client);
16 | let mine_sync = await api.mine_sync(http_client);
17 | let cards_to_upgrade = [];
18 | if (_.isEmpty(profile_data) || _.isEmpty(mine_sync) || _.isEmpty(cards_wc)) {
19 | return;
20 | }
21 | const not_upgraded_cards = filterArray.getNotUpgradeCards(
22 | mine_sync,
23 | cards_wc
24 | );
25 |
26 | if (!_.isEmpty(not_upgraded_cards)) {
27 | cards_to_upgrade = not_upgraded_cards;
28 | } else {
29 | cards_to_upgrade = cards_wc;
30 | }
31 |
32 | for (const [index, card] of cards_to_upgrade.entries()) {
33 | // Get current card information
34 | const singleCard = filterArray.getById(mine_sync, card?.upgradeId)[0];
35 |
36 | if (_.isEmpty(singleCard) || _.isEmpty(profile_data)) {
37 | break;
38 | }
39 |
40 | // Check the previous card's level before upgrading the current card
41 | if (index > 0) {
42 | const prevCard = filterArray.getById(
43 | mine_sync,
44 | cards_to_upgrade[index - 1]?.upgradeId
45 | )[0];
46 |
47 | // If the previous card's level is less than or equal to the current card's level, break the loop
48 | if (
49 | prevCard?.level <= singleCard?.level ||
50 | singleCard?.price > profile_data?.clicker?.balance
51 | ) {
52 | break;
53 | }
54 | }
55 |
56 | // Now check and upgrade the current card
57 | if (
58 | singleCard?.price <= profile_data?.clicker?.balance &&
59 | singleCard?.price <= settings.MAX_CARD_PRICE &&
60 | singleCard?.level <= settings.MAX_CARD_LEVEL &&
61 | singleCard?.isCompleted === false
62 | ) {
63 | const upgraded_card = await api.upgrade_cards(http_client, {
64 | upgradeId: card?.upgradeId,
65 | });
66 |
67 | if (upgraded_card?.status?.toLowerCase() === "ok") {
68 | logger.info(
69 | `[${bot_name}] | ${session_name} | Card upgraded to level: ${
70 | upgraded_card?.upgradesTask?.level > 1
71 | ? upgraded_card?.upgradesTask?.level - 1
72 | : 1
73 | } | Card: ${
74 | upgraded_card?.upgradesTask?.upgradeId
75 | } | Cost: ${singleCard?.price}
`
76 | );
77 | } else if (
78 | typeof upgraded_card === "string" &&
79 | upgraded_card?.includes("insufficient")
80 | ) {
81 | logger.info(
82 | `[${bot_name}] | ${session_name} | Insufficient balance to upgrade card | Card: ${card?.upgradeId}`
83 | );
84 | break;
85 | } else {
86 | logger.warning(
87 | `[${bot_name}] | ${session_name} | Could not upgrade card | Card: ${card?.upgradeId}`
88 | );
89 | break;
90 | }
91 | // Refresh profile data and mine sync after upgrading the card
92 | profile_data = await api.get_user_data(http_client);
93 | mine_sync = await api.mine_sync(http_client);
94 | } else {
95 | break;
96 | }
97 | }
98 | }
99 |
100 | module.exports = upgradeTabCardsBuying;
101 |
--------------------------------------------------------------------------------
/bot/config/config.js:
--------------------------------------------------------------------------------
1 | const _isArray = require("../utils/_isArray");
2 |
3 | require("dotenv").config();
4 | const settings = {
5 | API_ID:
6 | process.env.API_ID && /^\d+$/.test(process.env.API_ID)
7 | ? parseInt(process.env.API_ID)
8 | : process.env.API_ID && !/^\d+$/.test(process.env.API_ID)
9 | ? "N/A"
10 | : undefined,
11 | API_HASH: process.env.API_HASH || "",
12 |
13 | AUTO_PLAY_ENIGMA: process.env.AUTO_PLAY_ENIGMA
14 | ? process.env.AUTO_PLAY_ENIGMA.toLowerCase() === "true"
15 | : true,
16 |
17 | AUTO_PLAY_COMBO: process.env.AUTO_PLAY_COMBO
18 | ? process.env.AUTO_PLAY_COMBO.toLowerCase() === "true"
19 | : true,
20 |
21 | APPLY_DAILY_FULL_ENERGY: process.env.APPLY_DAILY_FULL_ENERGY
22 | ? process.env.APPLY_DAILY_FULL_ENERGY.toLowerCase() === "true"
23 | : true,
24 |
25 | AUTO_CLAIM_REWARD: process.env.AUTO_CLAIM_REWARD
26 | ? process.env.AUTO_CLAIM_REWARD.toLowerCase() === "true"
27 | : true,
28 |
29 | AUTO_COMPLETE_TASKS: process.env.AUTO_COMPLETE_TASKS
30 | ? process.env.AUTO_COMPLETE_TASKS.toLowerCase() === "true"
31 | : true,
32 |
33 | AUTO_UPGRADE_TAP: process.env.AUTO_UPGRADE_TAP
34 | ? process.env.AUTO_UPGRADE_TAP.toLowerCase() === "true"
35 | : true,
36 |
37 | AUTO_CLAIM_EASTER_EGG: process.env.AUTO_CLAIM_EASTER_EGG
38 | ? process.env.AUTO_CLAIM_EASTER_EGG.toLowerCase() === "true"
39 | : true,
40 |
41 | MAX_TAP_LEVEL: process.env.MAX_TAP_LEVEL
42 | ? parseInt(process.env.MAX_TAP_LEVEL)
43 | : 10,
44 |
45 | AUTO_UPGRADE_CARD: process.env.AUTO_UPGRADE_CARD
46 | ? process.env.AUTO_UPGRADE_CARD.toLowerCase() === "true"
47 | : true,
48 |
49 | MAX_CARD_LEVEL: process.env.MAX_CARD_LEVEL
50 | ? parseInt(process.env.MAX_CARD_LEVEL)
51 | : 10,
52 |
53 | MAX_CARD_PRICE: process.env.MAX_CARD_PRICE
54 | ? parseInt(process.env.MAX_CARD_PRICE)
55 | : 100000000000000,
56 |
57 | AUTO_HOURLY_LIMIT: process.env.AUTO_HOURLY_LIMIT
58 | ? process.env.AUTO_HOURLY_LIMIT.toLowerCase() === "true"
59 | : true,
60 |
61 | MAX_HOURLY_LIMIT_LEVEL: process.env.MAX_HOURLY_LIMIT_LEVEL
62 | ? parseInt(process.env.MAX_HOURLY_LIMIT_LEVEL)
63 | : 10,
64 |
65 | SLEEP_EMPTY_ENERGY: process.env.SLEEP_EMPTY_ENERGY
66 | ? parseInt(process.env.SLEEP_EMPTY_ENERGY)
67 | : 70,
68 |
69 | AUTO_UPGRADE_ENERGY_LIMIT: process.env.AUTO_UPGRADE_ENERGY_LIMIT
70 | ? process.env.AUTO_UPGRADE_ENERGY_LIMIT.toLowerCase() === "true"
71 | : true,
72 |
73 | RANDOM_TAPS_COUNT:
74 | process.env.RANDOM_TAPS_COUNT && _isArray(process.env.RANDOM_TAPS_COUNT)
75 | ? JSON.parse(process.env.RANDOM_TAPS_COUNT)
76 | : [300, 600],
77 |
78 | SLEEP_BETWEEN_TAP:
79 | process.env.SLEEP_BETWEEN_TAP && _isArray(process.env.SLEEP_BETWEEN_TAP)
80 | ? JSON.parse(process.env.SLEEP_BETWEEN_TAP)
81 | : process.env.SLEEP_BETWEEN_TAP &&
82 | /^\d+$/.test(process.env.SLEEP_BETWEEN_TAP)
83 | ? parseInt(process.env.SLEEP_BETWEEN_TAP)
84 | : 150,
85 |
86 | MAX_ENERGY_LIMIT_LEVEL: process.env.MAX_ENERGY_LIMIT_LEVEL
87 | ? parseInt(process.env.MAX_ENERGY_LIMIT_LEVEL)
88 | : 10,
89 |
90 | USE_PROXY_FROM_FILE: process.env.USE_PROXY_FROM_FILE
91 | ? process.env.USE_PROXY_FROM_FILE.toLowerCase() === "true"
92 | : false,
93 |
94 | USE_QUERY_ID: process.env.USE_QUERY_ID
95 | ? process.env.USE_QUERY_ID.toLowerCase() === "true"
96 | : false,
97 |
98 | MIN_AVAILABLE_ENERGY: process.env.MIN_AVAILABLE_ENERGY
99 | ? parseInt(process.env.MIN_AVAILABLE_ENERGY)
100 | : 100,
101 | };
102 |
103 | module.exports = settings;
104 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > [
](https://t.me/roddyfred)
2 |
3 | 
4 |
5 | # Use Node.Js 18 or greater
6 |
7 | ## Functionality
8 |
9 | | Functional | Supported |
10 | | ------------------------------------- | :-------: |
11 | | Claiming of daily combo | ✅ |
12 | | Claiming of daily enigma | ✅ |
13 | | Claiming of daily easter eggs | ✅ |
14 | | Claiming daily rewards | ✅ |
15 | | Completing tasks | ✅ |
16 | | Applying boosts | ✅ |
17 | | Upgrading taps | ✅ |
18 | | Upgrading hourly limit | ✅ |
19 | | Upgrading energy limit | ✅ |
20 | | Upgrading cards limit | ✅ |
21 | | Tapping | ✅ |
22 | | Data caching | ✅ |
23 | | Multithreading | ✅ |
24 | | Use sessions/query_ids | ✅ |
25 | | Binding a proxy to a session/query_id | ✅ |
26 | | Random sleep time between clicks | ✅ |
27 | | Random number of taps | ✅ |
28 |
29 | ## [How to add query id](https://github.com/Freddywhest/RockyRabbitBot/blob/main/AddQueryId.md)
30 |
31 | ## [Settings](https://github.com/FreddyWhest/RockyRabbitBot/blob/main/.env-example)
32 |
33 | | Settings | Description |
34 | | ----------------------------- | ------------------------------------------------------------------------- |
35 | | **API_ID / API_HASH** | Platform data from which to launch a Telegram session (stock - Android) |
36 | | **AUTO_PLAY_ENIGMA** | Whether to apply daily enigma (True / False) |
37 | | **AUTO_PLAY_COMBO** | Whether to apply daily combo (True / False) |
38 | | **AUTO_COMPLETE_TASKS** | Whether to complete tasks (True / False) |
39 | | **AUTO_UPGRADE_CARD** | Whether to upgrade cards to increase the passive earn (True / False) |
40 | | **MAX_CARD_LEVEL** | Maximum cards level (eg 20) |
41 | | **MAX_CARD_PRICE** | Maximum cards upgrade price (eg 50000000) |
42 | | **AUTO_UPGRADE_TAP** | Whether to upgrade taps (True / False) |
43 | | **MAX_TAP_LEVEL** | Maximum tap level (eg 20) |
44 | | **AUTO_HOURLY_LIMIT** | Whether to upgrade hourly limit (True / False) |
45 | | **MAX_HOURLY_LIMIT_LEVEL** | Maximum hourly limit level |
46 | | **AUTO_UPGRADE_ENERGY_LIMIT** | Whether to upgrade energy limit (True / False) |
47 | | **MAX_ENERGY_LIMIT_LEVEL** | Maximum energy limit level (eg 20) |
48 | | **APPLY_DAILY_FULL_ENERGY** | Whether to apply daily full energy (True / False) |
49 | | **AUTO_CLAIM_REWARD** | Whether to claim the daily rewards (True / False) |
50 | | **AUTO_CLAIM_EASTER_EGG** | Whether to claim the easter eggs (True / False) |
51 | | **USE_QUERY_ID** | Whether to use query ids instead of sessions (True / False) |
52 | | **RANDOM_TAPS_COUNT** | Random number of taps (eg [100,200]) |
53 | | **SLEEP_BETWEEN_TAP** | Random delay between taps in seconds (eg [50,60]) |
54 | | **SLEEP_EMPTY_ENERGY** | Delay when energy is empty (eg 70) |
55 | | **USE_PROXY_FROM_FILE** | Whether to use proxy from the `bot/config/proxies.js` file (True / False) |
56 |
57 | ## Installation
58 |
59 | You can download [**Repository**](https://github.com/FreddyWhest/RockyRabbitBot) by cloning it to your system and installing the necessary dependencies:
60 |
61 | ```shell
62 | ~ >>> git clone https://github.com/FreddyWhest/RockyRabbitBot.git
63 | ~ >>> cd RockyRabbitBot
64 |
65 | #Linux and MocOS
66 | ~/RockyRabbitBot >>> chmod +x check_node.sh
67 | ~/RockyRabbitBot >>> ./check_node.sh
68 |
69 | OR
70 |
71 | ~/RockyRabbitBot >>> npm install
72 | ~/RockyRabbitBot >>> cp .env-example .env
73 | ~/RockyRabbitBot >>> nano .env # Here you must specify your API_ID and API_HASH , the rest is taken by default
74 | ~/RockyRabbitBot >>> node index.js
75 |
76 | #Windows
77 | 1. Double click on INSTALL.bat in RockyRabbitBot directory to install the dependencies
78 | 2. Double click on START.bat in RockyRabbitBot directory to start the bot
79 |
80 | OR
81 |
82 | ~/RockyRabbitBot >>> npm install
83 | ~/RockyRabbitBot >>> cp .env-example .env
84 | ~/RockyRabbitBot >>> # Specify your API_ID and API_HASH, the rest is taken by default
85 | ~/RockyRabbitBot >>> node index.js
86 | ```
87 |
88 | Also for quick launch you can use arguments, for example:
89 |
90 | ```shell
91 | ~/RockyRabbitBot >>> node index.js --action=1
92 |
93 | OR
94 |
95 | ~/RockyRabbitBot >>> node index.js --action=2
96 |
97 | #1 - Create session
98 | #2 - Run clicker
99 | ```
100 |
--------------------------------------------------------------------------------
/bot/utils/logger.js:
--------------------------------------------------------------------------------
1 | const moment = require("moment");
2 |
3 | class Logger {
4 | constructor() {
5 | this.prefix = `[${moment().format("YYYY-MM-DD HH:mm:ss")}]`;
6 | this.GREEN = "\u001b[32m";
7 | this.RED = "\u001b[31m";
8 | this.YELLOW = "\u001b[33m";
9 | this.BLUE = "\u001b[34m";
10 | this.VOILET = "\u001b[35m";
11 | this.LIGHT_BLUE = "\u001b[36m";
12 | this.WHITE = "\u001b[37m";
13 | this.PINK = "\u001b[38;5;201m";
14 | this.LAVENDER = "\u001b[38;5;147m";
15 |
16 | //Background colors
17 | this.BG_WHITE_CYAN = "\u001b[37;46m";
18 | this.BG_RED = "\u001b[37;41m";
19 | this.BG_GREEN = "\u001b[37;42m";
20 | this.BG_YELLOW = "\u001b[37;43m";
21 | this.BG_BLUE = "\u001b[37;44m";
22 | this.BG_LIGHT_BLUE = "\u001b[37;45m";
23 | this.BG_WHITE = "\u001b[47;45m";
24 |
25 | this.RESET = "\u001b[0m";
26 | this.BOLD = "\u001b[1m";
27 | this.ITALICIZE = "\u001b[3m";
28 | this.UNDERLINE = "\u001b[4m";
29 | }
30 |
31 | #convertHtmlElementToAnsiColor(message) {
32 | if (!message) {
33 | return message;
34 | }
35 |
36 | return (
37 | message
38 | // Text colors
39 | .replace(//g, this.BLUE)
40 | .replace(/<\/bl>/g, this.RESET)
41 | .replace(//g, this.RED)
42 | .replace(/<\/re>/g, this.RESET)
43 | .replace(//g, this.GREEN)
44 | .replace(/<\/gr>/g, this.RESET)
45 | .replace(//g, this.YELLOW)
46 | .replace(/<\/ye>/g, this.RESET)
47 | .replace(//g, this.PINK)
48 | .replace(/<\/pi>/g, this.RESET)
49 | .replace(//g, this.WHITE)
50 | .replace(/<\/wh>/g, this.RESET)
51 | .replace(//g, this.VOILET)
52 | .replace(/<\/vo>/g, this.RESET)
53 | .replace(//g, this.LAVENDER)
54 | .replace(/<\/la>/g, this.RESET)
55 | .replace(//g, this.LIGHT_BLUE)
56 | .replace(/<\/lb>/g, this.RESET)
57 |
58 | // Text styles
59 | .replace(//g, this.BOLD)
60 | .replace(/<\/b>/g, this.RESET)
61 | .replace(//g, this.ITALICIZE)
62 | .replace(/<\/i>/g, this.RESET)
63 | .replace(//g, this.UNDERLINE)
64 | .replace(/<\/u>/g, this.RESET)
65 |
66 | // Background colors
67 | .replace(//g, this.BG_WHITE_CYAN)
68 | .replace(/<\/wcb>/g, this.RESET)
69 | .replace(//g, this.BG_RED)
70 | .replace(/<\/reb>/g, this.RESET)
71 | .replace(//g, this.BG_GREEN)
72 | .replace(/<\/grb>/g, this.RESET)
73 | .replace(//g, this.BG_YELLOW)
74 | .replace(/<\/yeb>/g, this.RESET)
75 | .replace(//g, this.BG_BLUE)
76 | .replace(/<\/blb>/g, this.RESET)
77 | .replace(//g, this.BG_LIGHT_BLUE)
78 | .replace(/<\/lbb>/g, this.RESET)
79 | .replace(//g, this.BG_WHITE)
80 | .replace(/<\/whb>/g, this.RESET)
81 |
82 | // HTML tags
83 | .replace(/
/g, "\n")
84 | .replace(/
/g, "\n")
85 | );
86 | }
87 |
88 | info(message) {
89 | this.prefix = `[${moment().format("YYYY-MM-DD HH:mm:ss")}]`;
90 | console.log(
91 | this.#convertHtmlElementToAnsiColor(
92 | `${this.prefix} | INFO | ${message}`
93 | )
94 | );
95 | }
96 |
97 | warning(message) {
98 | this.prefix = `[${moment().format("YYYY-MM-DD HH:mm:ss")}]`;
99 | console.log(
100 | this.#convertHtmlElementToAnsiColor(
101 | `${this.prefix} | WARN | ${message}`
102 | )
103 | );
104 | }
105 |
106 | error(message) {
107 | this.prefix = `[${moment().format("YYYY-MM-DD HH:mm:ss")}]`;
108 | console.log(
109 | this.#convertHtmlElementToAnsiColor(
110 | `${this.prefix} | ERROR | ${message}`
111 | )
112 | );
113 | }
114 |
115 | debug(message) {
116 | this.prefix = `[${moment().format("YYYY-MM-DD HH:mm:ss")}]`;
117 | console.log(
118 | this.#convertHtmlElementToAnsiColor(
119 | `${this.prefix} | DEBUG | ${message}`
120 | )
121 | );
122 | }
123 |
124 | success(message) {
125 | this.prefix = `[${moment().format("YYYY-MM-DD HH:mm:ss")}]`;
126 | console.log(
127 | this.#convertHtmlElementToAnsiColor(
128 | `${this.prefix} | SUCCESS | ${message}`
129 | )
130 | );
131 | }
132 |
133 | #stripAnsiCodes(text) {
134 | const ansiRegex = /\x1b\[[0-9;]*m/g;
135 | return text.replace(ansiRegex, "");
136 | }
137 |
138 | #addRoundedBorder(logText) {
139 | const lines = logText.split("\n");
140 |
141 | const maxLength = lines.reduce(
142 | (max, line) => Math.max(max, this.#stripAnsiCodes(line).length),
143 | 0
144 | );
145 |
146 | const topBorder = `${this.BLUE}╭${"─".repeat(maxLength + 2)}╮${this.RESET}`;
147 | const bottomBorder = `${this.BLUE}╰${"─".repeat(maxLength + 2)}╯${
148 | this.RESET
149 | }`;
150 | console.log(topBorder);
151 | lines.forEach((line) => {
152 | const strippedLineLength = this.#stripAnsiCodes(line).length;
153 | console.log(
154 | `${this.BLUE}│${this.RESET} ${line}${" ".repeat(
155 | maxLength - strippedLineLength
156 | )} ${this.BLUE}│${this.RESET}`
157 | );
158 | });
159 | console.log(bottomBorder);
160 | }
161 |
162 | paragraph(message) {
163 | this.prefix = `[${moment().format("YYYY-MM-DD HH:mm:ss")}]`;
164 | this.#addRoundedBorder(
165 | this.#convertHtmlElementToAnsiColor(
166 | `${this.prefix}
167 | ${message}`
168 | )
169 | );
170 | }
171 | }
172 |
173 | const logger = new Logger();
174 |
175 | module.exports = logger;
176 |
--------------------------------------------------------------------------------
/bot/utils/luncher.js:
--------------------------------------------------------------------------------
1 | const a0_0x111aea=a0_0x2aef;function a0_0x4f83(){const _0x38bb10=['showHelpAfterError','error','.session','readdirSync','USE_PROXY_FROM_FILE','endsWith','split','4212882DhCqIm','path','process','
\x20sessions\x20|\x20','cwd','sessions','48knDGjV','11930XvjnYm','all','Freddy\x20Bots','1404008hJQqYA','API_ID','2922vdihXz','exit','55LRkwgh','35NMLlxg','trim','choices','1.0.0','\x0aCreate\x20a\x20new\x20session\x20for\x20the\x20bot','Action\x20must\x20be\x201\x20or\x202','149242rFUcxP','35508492JiCCnF','iterator','map','apiId','100668mqqIDB','../config/app','run','14JCCWrk','../config/config','./TldLogger','ENOENT','apiHash','exports','parse','\x20proxies','../config/proxies','../core/tapper','Create\x20session','message','API_ID\x20and\x20API_HASH\x20must\x20be\x20provided.','sessionString','Error\x20in\x20task\x20for\x20tg_client:\x20','paragraph','readFileSync','addOption','telegram','Detected\x20','length','Action\x20type','\x0a╔═══╗\x20\x20\x20\x20\x20\x20\x20\x20╔╗\x20\x20\x20\x20\x20\x20\x20╔═══╗\x20\x20\x20\x20\x20╔╗\x20\x20╔╗\x20\x20\x20\x20\x20╔╗\x20╔══╗\x20\x20\x20\x20\x20\x20╔╗\x20\x0a║╔═╗║\x20\x20\x20\x20\x20\x20\x20\x20║║\x20\x20\x20\x20\x20\x20\x20║╔═╗║\x20\x20\x20\x20\x20║║\x20\x20║║\x20\x20\x20\x20╔╝╚╗║╔╗║\x20\x20\x20\x20\x20╔╝╚╗\x0a║╚═╝║╔══╗╔══╗║║╔╗╔╗\x20╔╗║╚═╝║╔══╗\x20║╚═╗║╚═╗╔╗╚╗╔╝║╚╝╚╗╔══╗╚╗╔╝\x0a║╔╗╔╝║╔╗║║╔═╝║╚╝╝║║\x20║║║╔╗╔╝╚\x20╗║\x20║╔╗║║╔╗║╠╣\x20║║\x20║╔═╗║║╔╗║\x20║║\x20\x0a║║║╚╗║╚╝║║╚═╗║╔╗╗║╚═╝║║║║╚╗║╚╝╚╗║╚╝║║╚╝║║║\x20║╚╗║╚═╝║║╚╝║\x20║╚╗\x0a╚╝╚═╝╚══╝╚══╝╚╝╚╝╚═╗╔╝╚╝╚═╝╚═══╝╚══╝╚══╝╚╝\x20╚═╝╚═══╝╚══╝\x20╚═╝\x0a©\x20Freddy\x20Bots\x20\x20\x20\x20╔═╝║\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20╚══╝\x20\x0a\x0a\x0a','utf8','value','opts','
\x20|\x20Invalid\x20session\x20data.\x20Create\x20a\x20new\x20one.','version','This\x20bot\x20has\x20been\x20compromised\x20and\x20is\x20no\x20longer\x20functioning.\x0aGo\x20to\x20https://github.com/FreddyWhest/RockyRabbitBot
\x20to\x20download\x20the\x20latest\x20and\x20working\x20version.','log','\x20|\x20Session\x20is\x20empty\x20or\x20expired.\x20Create\x20a\x20new\x20one.','1017370YLkPqb','','@inquirer/prompts','join'];a0_0x4f83=function(){return _0x38bb10;};return a0_0x4f83();}(function(_0x21d6d1,_0x36ab41){const _0x557525=a0_0x2aef,_0xae02c1=_0x21d6d1();while(!![]){try{const _0x3496d9=parseInt(_0x557525(0x149))/0x1*(parseInt(_0x557525(0x141))/0x2)+-parseInt(_0x557525(0x146))/0x3*(parseInt(_0x557525(0x179))/0x4)+-parseInt(_0x557525(0x17a))/0x5*(parseInt(_0x557525(0x17f))/0x6)+parseInt(_0x557525(0x182))/0x7*(-parseInt(_0x557525(0x17d))/0x8)+-parseInt(_0x557525(0x173))/0x9+parseInt(_0x557525(0x168))/0xa*(-parseInt(_0x557525(0x181))/0xb)+parseInt(_0x557525(0x142))/0xc;if(_0x3496d9===_0x36ab41)break;else _0xae02c1['push'](_0xae02c1['shift']());}catch(_0xa60793){_0xae02c1['push'](_0xae02c1['shift']());}}}(a0_0x4f83,0x8ec59));const register=require('../core/register'),logger=require('./logger'),{select}=require(a0_0x111aea(0x16a)),fs=require('fs'),path=require(a0_0x111aea(0x174)),settings=require(a0_0x111aea(0x14a)),proxies=require(a0_0x111aea(0x151)),{program,Option}=require('commander'),{TelegramClient}=require(a0_0x111aea(0x15b)),Tapper=require(a0_0x111aea(0x152)),{StringSession}=require('telegram/sessions'),logger2=require(a0_0x111aea(0x14b)),app=require(a0_0x111aea(0x147));function a0_0x2aef(_0x49dfb3,_0x9a72c8){const _0x4f834c=a0_0x4f83();return a0_0x2aef=function(_0x2aefa1,_0xf4ad07){_0x2aefa1=_0x2aefa1-0x13d;let _0x87f253=_0x4f834c[_0x2aefa1];return _0x87f253;},a0_0x2aef(_0x49dfb3,_0x9a72c8);}class Luncher{#start_text;constructor(){const _0x366e4f=a0_0x111aea;this.#start_text=_0x366e4f(0x15f);}async #printStartText(){const _0x2794f9=a0_0x111aea;logger['info'](_0x2794f9(0x15c)+this.#get_sessions()[_0x2794f9(0x15d)]+_0x2794f9(0x176)+(this.#get_proxies()&&Array['isArray'](this.#get_proxies())?this.#get_proxies()[_0x2794f9(0x15d)]:0x0)+_0x2794f9(0x150)),logger[_0x2794f9(0x158)]('WARNING\x20
\x0aen:\x20NOT\x20FOR\x20SALE\x0aru:\x20НЕ\x20ДЛЯ\x20ПРОДАЖИ\x0aes:\x20NO\x20VENTA\x0afr:\x20PAS\x20À\x20VENDRE\x0ait:\x20NON\x20PER\x20VENDITA\x0agh:\x20YƐN\x20TƆN\x0a\x0aFor\x20updates\x20and\x20more\x20bots\x20join\x20us:\x20\x0ahttps://t.me/freddy_bots\x0a\x0aBot:\x20'+app['botName']+'\x0aVersion:\x20'+app[_0x2794f9(0x164)]+'\x0a'),console[_0x2794f9(0x166)](this.#start_text);}async[a0_0x111aea(0x175)](){const _0x4ef318=a0_0x111aea;try{let _0x7448e3;program[_0x4ef318(0x15a)](new Option('--action\x20',_0x4ef318(0x15e))[_0x4ef318(0x13d)](['1','2']))[_0x4ef318(0x16c)](!![]),program['parse']();const _0x30115d=program[_0x4ef318(0x162)]();_0x7448e3=_0x30115d?parseInt(_0x30115d['action']):null;if(!_0x7448e3){this.#printStartText();let _0x39578f='';while(!![]){_0x39578f=await select({'message':'What\x20would\x20you\x20like\x20to\x20do:\x0a','choices':[{'name':_0x4ef318(0x153),'value':'1','description':_0x4ef318(0x13f)},{'name':'Run\x20bot','value':'2','description':'\x0aStart\x20the\x20bot'}]});if(!_0x39578f[_0x4ef318(0x183)]()['match'](/^[1-2]$/))logger['warning'](_0x4ef318(0x140));else break;}_0x7448e3=parseInt(_0x39578f[_0x4ef318(0x183)]());}if(_0x7448e3===0x1)register['start']();else{if(_0x7448e3===0x2){const _0x47f4bc=await this.#get_tg_clients();await this.#run_tasks(_0x47f4bc);}}}catch(_0x513a7f){if(_0x513a7f?.[_0x4ef318(0x154)]?.['includes'](_0x4ef318(0x14c)))return logger['error'](_0x4ef318(0x165));logger[_0x4ef318(0x16d)](_0x513a7f?.[_0x4ef318(0x154)]);}}async #get_tg_clients(){const _0x13443b=this.#get_sessions(),_0x24fdbe=_0x13443b['map'](_0x48cb7b=>{const _0x2bf394=a0_0x2aef;try{const _0x130025=fs[_0x2bf394(0x159)](path[_0x2bf394(0x16b)](process[_0x2bf394(0x177)](),_0x2bf394(0x178),_0x48cb7b+'.session'),_0x2bf394(0x160));if(!_0x130025){logger[_0x2bf394(0x16d)](_0x2bf394(0x169)+_0x48cb7b+_0x2bf394(0x167));return;}const _0x4f552d=JSON[_0x2bf394(0x14f)](_0x130025);(!settings[_0x2bf394(0x17e)]||!settings['API_HASH'])&&(logger[_0x2bf394(0x16d)](_0x2bf394(0x155)),process[_0x2bf394(0x180)](0x1));(!_0x4f552d['sessionString']||!_0x4f552d[_0x2bf394(0x145)]||!_0x4f552d[_0x2bf394(0x14d)])&&(logger['error'](''+_0x48cb7b+_0x2bf394(0x163)),process[_0x2bf394(0x180)](0x1));!/^\d+$/['test'](_0x4f552d[_0x2bf394(0x145)])&&(logger['error'](''+_0x48cb7b+_0x2bf394(0x163)),process[_0x2bf394(0x180)](0x1));const _0x279deb=new StringSession(_0x4f552d[_0x2bf394(0x156)]),_0x339cff=new TelegramClient(_0x279deb,_0x4f552d['apiId'],_0x4f552d[_0x2bf394(0x14d)],{'connectionRetries':0x5,'deviceModel':_0x2bf394(0x17c),'appVersion':_0x2bf394(0x13e),'systemVersion':'1.0.0','langCode':'en','baseLogger':logger2});return{'tg_client':_0x339cff,'session_name':_0x48cb7b};}catch(_0x273d8c){logger[_0x2bf394(0x16d)](_0x2bf394(0x169)+_0x48cb7b+'\x20|\x20Error:\x20'+_0x273d8c[_0x2bf394(0x154)]);}});return _0x24fdbe;}#get_sessions(){const _0x23768e=a0_0x111aea,_0x5116d9=path[_0x23768e(0x16b)](process[_0x23768e(0x177)](),_0x23768e(0x178));if(!fs['existsSync'](_0x5116d9))return[];const _0x203ad3=fs[_0x23768e(0x16f)](_0x5116d9)[_0x23768e(0x144)](_0x2221bf=>{const _0xe31501=_0x23768e,_0x388299=_0x2221bf[_0xe31501(0x171)](_0xe31501(0x16e))?_0x2221bf[_0xe31501(0x172)]('.')[0x0]:null;return _0x388299;});return _0x203ad3;}#get_proxies(){const _0x10493d=a0_0x111aea;if(!settings[_0x10493d(0x170)])return null;return proxies;}async #run_tasks(_0x2b74b7){const _0x2e047a=a0_0x111aea,_0x1242c2=this.#get_proxies();let _0x18a580=_0x1242c2?_0x1242c2[Symbol[_0x2e047a(0x143)]]():null;const _0xcbc6b9=_0x2b74b7[_0x2e047a(0x144)](async _0x42fbe5=>{const _0x38bee4=_0x2e047a,_0x271d9d=_0x18a580?_0x18a580['next']()[_0x38bee4(0x161)]:null;try{await new Tapper(_0x42fbe5)[_0x38bee4(0x148)](_0x271d9d);}catch(_0x1cded2){logger[_0x38bee4(0x16d)](_0x38bee4(0x157)+_0x1cded2['message']);}});await Promise[_0x2e047a(0x17b)](_0xcbc6b9);}}const luncher=new Luncher();module[a0_0x111aea(0x14e)]=luncher;
--------------------------------------------------------------------------------
/bot/core/register.js:
--------------------------------------------------------------------------------
1 | const { TelegramClient, sessions } = require("telegram");
2 | const { StringSession } = require("telegram/sessions");
3 | const fs = require("fs");
4 | const { input } = require("@inquirer/prompts");
5 | const logger = require("../utils/logger");
6 | const settings = require("../config/config");
7 | require("dotenv").config();
8 | const path = require("path");
9 | const logger2 = require("../utils/TldLogger");
10 | const devices = require("../utils/devices");
11 | const { select } = require("@inquirer/prompts");
12 | var qrcode = require("qrcode-terminal");
13 | const readline = require("readline");
14 | const os = require("os");
15 | const { version } = require("../../package.json");
16 |
17 | class Register {
18 | #stringSession;
19 | #apiId;
20 | #apiHash;
21 | constructor() {
22 | this.#apiId = settings.API_ID;
23 | this.#apiHash = settings.API_HASH;
24 | this.#stringSession = new StringSession("");
25 | }
26 |
27 | async #getSessionName() {
28 | const filePath = path.join(process.cwd(), "sessions");
29 | let sessionsName = await input({
30 | message: "Please enter your session name: ",
31 | });
32 | do {
33 | if (fs.existsSync(`${filePath}/${sessionsName}.session`)) {
34 | logger.warning(`Session name ${sessionsName} already exists!`);
35 | sessionsName = await input({
36 | message: "Please enter a different session name: ",
37 | });
38 | }
39 | } while (fs.existsSync(`${filePath}/${sessionsName}.session`));
40 | return sessionsName;
41 | }
42 |
43 | #load_simulate_device() {
44 | try {
45 | const filePath = path.join(process.cwd(), "simulate_device.json");
46 | const data = fs.readFileSync(filePath, "utf8");
47 | return JSON.parse(data);
48 | } catch (error) {
49 | if (error.code === "ENOENT") {
50 | return {};
51 | } else {
52 | throw error;
53 | }
54 | }
55 | }
56 |
57 | #get_random_simulate_device() {
58 | const randomIndex = Math.floor(Math.random() * devices.length);
59 | return devices[randomIndex];
60 | }
61 |
62 | #get_simulate_device() {
63 | const simulate_device = this.#load_simulate_device();
64 | const requiredKeys = ["manufacturer", "model", "cpu", "type", "os"];
65 | const containsKeys = requiredKeys.every((key) => key in simulate_device);
66 | if (containsKeys) {
67 | return simulate_device;
68 | }
69 | logger.info("Simulate device not found. Generating one...");
70 | const random_device = this.#get_random_simulate_device();
71 | this.#save_simulate_device(random_device);
72 | return random_device;
73 | }
74 |
75 | #save_simulate_device(simulate_device) {
76 | const filePath = path.join(process.cwd(), "simulate_device.json");
77 | fs.writeFileSync(filePath, JSON.stringify(simulate_device, null, 2));
78 | }
79 |
80 | #client() {
81 | const client_options = {
82 | connectionRetries: 5,
83 | deviceModel: os.type(),
84 | appVersion: "1.0.0",
85 | systemVersion: "1.0.0",
86 | langCode: "en",
87 | baseLogger: logger2,
88 | };
89 |
90 | const client = new TelegramClient(
91 | this.#stringSession,
92 | this.#apiId,
93 | this.#apiHash,
94 | client_options
95 | );
96 |
97 | return client;
98 | }
99 |
100 | async #sign_in_with_phone(client) {
101 | await client.start({
102 | phoneNumber: async () =>
103 | await input({
104 | message: "Please enter your number: ",
105 | }),
106 | password: async () =>
107 | await input({
108 | message: "Please enter your password: ",
109 | }),
110 | phoneCode: async () =>
111 | await input({
112 | message: "Please enter the code you received: ",
113 | }),
114 | onError: (err) => console.error(err),
115 | });
116 | }
117 |
118 | async #sign_in_with_qr(client) {
119 | let qrCodeLines = 0;
120 | let message = "";
121 | await client.connect();
122 | let isShown = false;
123 | await client.signInUserWithQrCode(
124 | { apiId: this.#apiId, apiHash: this.#apiHash },
125 | {
126 | onError: (err) => console.error(err),
127 | qrCode: async (code) => {
128 | if (!isShown) {
129 | console.log(
130 | "\nScan QR code below with your telegram app to login: \n"
131 | );
132 | qrcode.generate(
133 | `tg://login?token=${code.token.toString("base64url")}`,
134 | { small: true },
135 | (qrcodeString) => {
136 | qrCodeLines = qrcodeString.split("\n").length; // Count the lines in the QR code
137 | console.log(qrcodeString);
138 | }
139 | );
140 | isShown = true;
141 | } else {
142 | if (message) {
143 | qrCodeLines = qrCodeLines + 2;
144 | }
145 | readline.moveCursor(process.stdout, 0, -qrCodeLines); // Adjust -6 based on the number of lines your QR code takes
146 | readline.clearScreenDown(process.stdout); // Clear everything below the cursor
147 | message = "\nNew qr code received\n";
148 | console.log(message);
149 | qrcode.generate(
150 | `tg://login?token=${code.token.toString("base64url")}`,
151 | { small: true },
152 | (qrcodeString) => {
153 | qrCodeLines = qrcodeString.split("\n").length + 2; // Count the lines in the QR code
154 | console.log(qrcodeString);
155 | }
156 | );
157 | }
158 | },
159 | password: async () =>
160 | await input({
161 | message: "Please enter your password: ",
162 | }),
163 | }
164 | );
165 | }
166 |
167 | async start() {
168 | const filePath = path.join(process.cwd(), "sessions");
169 | if (!this.#apiId || !this.#apiHash) {
170 | logger.error("API_ID and API_HASH must be provided.");
171 | process.exit(1);
172 | }
173 |
174 | if (typeof this.#apiHash !== "string" || typeof this.#apiId !== "number") {
175 | logger.error(
176 | "API_ID and API_HASH must be numbers and strings respectively."
177 | );
178 | process.exit(1);
179 | }
180 |
181 | const simulate_device = this.#get_simulate_device();
182 |
183 | const sessionsName = await this.#getSessionName();
184 |
185 | // Here we are creating a new session
186 |
187 | let userInput = "";
188 |
189 | while (true) {
190 | userInput = await select({
191 | message: "How do you want to create a new session:\n",
192 | choices: [
193 | {
194 | name: "With QR code",
195 | value: "1",
196 | description: "\nCreate a new session with QR code",
197 | },
198 | {
199 | name: "With phone number",
200 | value: "2",
201 | description: "\nCreate a new session with phone number",
202 | },
203 | ],
204 | });
205 |
206 | if (!userInput.trim().match(/^[1-2]$/)) {
207 | logger.warning("Action must be 1 or 2");
208 | } else {
209 | break;
210 | }
211 | }
212 |
213 | const action = parseInt(userInput.trim());
214 |
215 | if (action === 1) {
216 | await this.#sign_in_with_qr(this.#client());
217 | } else if (action === 2) {
218 | await this.#sign_in_with_phone(this.#client());
219 | }
220 |
221 | if (!fs.existsSync(filePath)) {
222 | fs.mkdirSync(filePath);
223 | }
224 |
225 | const sessionData = {
226 | apiId: this.#apiId,
227 | apiHash: this.#apiHash,
228 | sessionString: this.#stringSession.save(),
229 | };
230 |
231 | fs.writeFileSync(
232 | `${filePath}/${sessionsName}.session`,
233 | JSON.stringify(sessionData, null, 2)
234 | );
235 |
236 | logger.paragraph(
237 | `Session saved as ${sessionsName}.session
238 | Session device info:
239 | OS: ${os.type() || "N/A"}
240 | `
241 | );
242 |
243 | this.#client().disconnect();
244 | process.exit(0);
245 | }
246 | }
247 |
248 | const register = new Register();
249 | module.exports = register;
250 |
--------------------------------------------------------------------------------
/bot/utils/devices.js:
--------------------------------------------------------------------------------
1 | const devices = [
2 | {
3 | manufacturer: "Apple",
4 | model: "iPhone 14 Pro",
5 | cpu: "A16 Bionic",
6 | type: "iPhone",
7 | os: "iOS 16",
8 | },
9 | {
10 | manufacturer: "Apple",
11 | model: "iPhone 13",
12 | cpu: "A15 Bionic",
13 | type: "iPhone",
14 | os: "iOS 15",
15 | },
16 | {
17 | manufacturer: "Apple",
18 | model: "iPhone SE (2022)",
19 | cpu: "A15 Bionic",
20 | type: "iPhone",
21 | os: "iOS 15",
22 | },
23 | {
24 | manufacturer: "Apple",
25 | model: "iPad Pro 2021",
26 | cpu: "M1",
27 | type: "iPad",
28 | os: "iPadOS 15",
29 | },
30 | {
31 | manufacturer: "Apple",
32 | model: 'MacBook Pro 16" 2021',
33 | cpu: "M1 Pro",
34 | type: "Laptop",
35 | os: "macOS Monterey",
36 | },
37 | {
38 | manufacturer: "Apple",
39 | model: "MacBook Air M2",
40 | cpu: "M2",
41 | type: "Laptop",
42 | os: "macOS Ventura",
43 | },
44 | {
45 | manufacturer: "Samsung",
46 | model: "Galaxy S21 Ultra",
47 | cpu: "Exynos 2100",
48 | type: "Android",
49 | os: "Android 11",
50 | },
51 | {
52 | manufacturer: "Samsung",
53 | model: "Galaxy Note 20",
54 | cpu: "Exynos 990",
55 | type: "Android",
56 | os: "Android 10",
57 | },
58 | {
59 | manufacturer: "Samsung",
60 | model: "Galaxy A52",
61 | cpu: "Qualcomm Snapdragon 720G",
62 | type: "Android",
63 | os: "Android 11",
64 | },
65 | {
66 | manufacturer: "Samsung",
67 | model: "Galaxy Tab S7",
68 | cpu: "Qualcomm Snapdragon 865+",
69 | type: "Android Tablet",
70 | os: "Android 10",
71 | },
72 | {
73 | manufacturer: "Samsung",
74 | model: "Galaxy Z Fold 3",
75 | cpu: "Qualcomm Snapdragon 888",
76 | type: "Android Foldable",
77 | os: "Android 11",
78 | },
79 | {
80 | manufacturer: "Google",
81 | model: "Pixel 6",
82 | cpu: "Google Tensor",
83 | type: "Android",
84 | os: "Android 12",
85 | },
86 | {
87 | manufacturer: "Google",
88 | model: "Pixel 5a",
89 | cpu: "Qualcomm Snapdragon 765G",
90 | type: "Android",
91 | os: "Android 11",
92 | },
93 | {
94 | manufacturer: "Google",
95 | model: "Pixel 4a",
96 | cpu: "Qualcomm Snapdragon 730G",
97 | type: "Android",
98 | os: "Android 11",
99 | },
100 | {
101 | manufacturer: "Microsoft",
102 | model: "Surface Laptop 4",
103 | cpu: "Intel Core i7-1185G7",
104 | type: "Laptop",
105 | os: "Windows 10",
106 | },
107 | {
108 | manufacturer: "Microsoft",
109 | model: "Surface Book 3",
110 | cpu: "Intel Core i7-1065G7",
111 | type: "Laptop",
112 | os: "Windows 10",
113 | },
114 | {
115 | manufacturer: "Dell",
116 | model: "XPS 13",
117 | cpu: "Intel Core i7-1185G7",
118 | type: "Laptop",
119 | os: "Windows 10",
120 | },
121 | {
122 | manufacturer: "Dell",
123 | model: "Inspiron 15 7000",
124 | cpu: "Intel Core i5-1035G1",
125 | type: "Laptop",
126 | os: "Windows 10",
127 | },
128 | {
129 | manufacturer: "HP",
130 | model: "Spectre x360 14",
131 | cpu: "Intel Core i7-1165G7",
132 | type: "Laptop",
133 | os: "Windows 10",
134 | },
135 | {
136 | manufacturer: "HP",
137 | model: "Envy 13",
138 | cpu: "Intel Core i5-1135G7",
139 | type: "Laptop",
140 | os: "Windows 10",
141 | },
142 | {
143 | manufacturer: "Lenovo",
144 | model: "ThinkPad X1 Carbon",
145 | cpu: "Intel Core i7-1165G7",
146 | type: "Laptop",
147 | os: "Windows 10",
148 | },
149 | {
150 | manufacturer: "Lenovo",
151 | model: "Yoga 9i",
152 | cpu: "Intel Core i7-1185G7",
153 | type: "Laptop",
154 | os: "Windows 10",
155 | },
156 | {
157 | manufacturer: "Asus",
158 | model: "ROG Strix Scar 15",
159 | cpu: "AMD Ryzen 9 5900HX",
160 | type: "Laptop",
161 | os: "Windows 10",
162 | },
163 | {
164 | manufacturer: "Asus",
165 | model: "ZenBook 14",
166 | cpu: "Intel Core i7-1165G7",
167 | type: "Laptop",
168 | os: "Windows 10",
169 | },
170 | {
171 | manufacturer: "Acer",
172 | model: "Predator Helios 300",
173 | cpu: "Intel Core i7-10750H",
174 | type: "Laptop",
175 | os: "Windows 10",
176 | },
177 | {
178 | manufacturer: "Acer",
179 | model: "Swift 3",
180 | cpu: "AMD Ryzen 7 4700U",
181 | type: "Laptop",
182 | os: "Windows 10",
183 | },
184 | {
185 | manufacturer: "Sony",
186 | model: "VAIO SX14",
187 | cpu: "Intel Core i7-1165G7",
188 | type: "Laptop",
189 | os: "Windows 10",
190 | },
191 | {
192 | manufacturer: "Razer",
193 | model: "Blade 15 Advanced",
194 | cpu: "Intel Core i7-10875H",
195 | type: "Laptop",
196 | os: "Windows 10",
197 | },
198 | {
199 | manufacturer: "Huawei",
200 | model: "MateBook X Pro",
201 | cpu: "Intel Core i5-10210U",
202 | type: "Laptop",
203 | os: "Windows 10",
204 | },
205 | {
206 | manufacturer: "Huawei",
207 | model: "MateBook 14",
208 | cpu: "AMD Ryzen 5 4600U",
209 | type: "Laptop",
210 | os: "Windows 10",
211 | },
212 | {
213 | manufacturer: "Xiaomi",
214 | model: "Mi 11 Ultra",
215 | cpu: "Qualcomm Snapdragon 888",
216 | type: "Android",
217 | os: "Android 11",
218 | },
219 | {
220 | manufacturer: "Xiaomi",
221 | model: "Redmi Note 11",
222 | cpu: "Qualcomm Snapdragon 680",
223 | type: "Android",
224 | os: "Android 11",
225 | },
226 | {
227 | manufacturer: "OnePlus",
228 | model: "OnePlus 9 Pro",
229 | cpu: "Qualcomm Snapdragon 888",
230 | type: "Android",
231 | os: "Android 11",
232 | },
233 | {
234 | manufacturer: "OnePlus",
235 | model: "OnePlus Nord",
236 | cpu: "Qualcomm Snapdragon 765G",
237 | type: "Android",
238 | os: "Android 11",
239 | },
240 | {
241 | manufacturer: "LG",
242 | model: "Gram 17",
243 | cpu: "Intel Core i7-1165G7",
244 | type: "Laptop",
245 | os: "Windows 10",
246 | },
247 | {
248 | manufacturer: "LG",
249 | model: "V60 ThinQ",
250 | cpu: "Qualcomm Snapdragon 865",
251 | type: "Android",
252 | os: "Android 10",
253 | },
254 | {
255 | manufacturer: "Motorola",
256 | model: "Moto G Power",
257 | cpu: "Qualcomm Snapdragon 662",
258 | type: "Android",
259 | os: "Android 10",
260 | },
261 | {
262 | manufacturer: "Motorola",
263 | model: "Moto Edge 2021",
264 | cpu: "Qualcomm Snapdragon 778G",
265 | type: "Android",
266 | os: "Android 11",
267 | },
268 | {
269 | manufacturer: "Nokia",
270 | model: "Nokia 8.3 5G",
271 | cpu: "Qualcomm Snapdragon 765G",
272 | type: "Android",
273 | os: "Android 10",
274 | },
275 | {
276 | manufacturer: "Nokia",
277 | model: "Nokia 7.2",
278 | cpu: "Qualcomm Snapdragon 660",
279 | type: "Android",
280 | os: "Android 10",
281 | },
282 | {
283 | manufacturer: "Dell",
284 | model: "G5 15",
285 | cpu: "Intel Core i7-10750H",
286 | type: "Laptop",
287 | os: "Windows 10",
288 | },
289 | {
290 | manufacturer: "HP",
291 | model: "Pavilion 15",
292 | cpu: "AMD Ryzen 5 5500U",
293 | type: "Laptop",
294 | os: "Windows 10",
295 | },
296 | {
297 | manufacturer: "Lenovo",
298 | model: "ThinkPad T14",
299 | cpu: "Intel Core i7-10610U",
300 | type: "Laptop",
301 | os: "Windows 10",
302 | },
303 | {
304 | manufacturer: "Asus",
305 | model: "TUF Gaming A15",
306 | cpu: "AMD Ryzen 7 4800H",
307 | type: "Laptop",
308 | os: "Windows 10",
309 | },
310 | {
311 | manufacturer: "Acer",
312 | model: "Nitro 5",
313 | cpu: "Intel Core i5-9300H",
314 | type: "Laptop",
315 | os: "Windows 10",
316 | },
317 | {
318 | manufacturer: "Razer",
319 | model: "Blade Stealth 13",
320 | cpu: "Intel Core i7-1165G7",
321 | type: "Laptop",
322 | os: "Windows 10",
323 | },
324 | {
325 | manufacturer: "Sony",
326 | model: "VAIO SX12",
327 | cpu: "Intel Core i7-1065G7",
328 | type: "Laptop",
329 | os: "Windows 10",
330 | },
331 | {
332 | manufacturer: "Huawei",
333 | model: "MateBook D 15",
334 | cpu: "AMD Ryzen 5 3500U",
335 | type: "Laptop",
336 | os: "Windows 10",
337 | },
338 | {
339 | manufacturer: "Xiaomi",
340 | model: "Mi Mix 4",
341 | cpu: "Qualcomm Snapdragon 888",
342 | type: "Android",
343 | os: "Android 11",
344 | },
345 | {
346 | manufacturer: "Google",
347 | model: "Pixel 6 Pro",
348 | cpu: "Google Tensor",
349 | type: "Android",
350 | os: "Android 12",
351 | },
352 | {
353 | manufacturer: "Google",
354 | model: "Pixel 5",
355 | cpu: "Qualcomm Snapdragon 765G",
356 | type: "Android",
357 | os: "Android 11",
358 | },
359 | {
360 | manufacturer: "Apple",
361 | model: "iPad Air (2022)",
362 | cpu: "M1",
363 | type: "iPad",
364 | os: "iPadOS 15",
365 | },
366 | {
367 | manufacturer: "Apple",
368 | model: "iPhone 11",
369 | cpu: "A13 Bionic",
370 | type: "iPhone",
371 | os: "iOS 14",
372 | },
373 | {
374 | manufacturer: "Samsung",
375 | model: "Galaxy A72",
376 | cpu: "Qualcomm Snapdragon 720G",
377 | type: "Android",
378 | os: "Android 11",
379 | },
380 | {
381 | manufacturer: "Samsung",
382 | model: "Galaxy S20 FE",
383 | cpu: "Exynos 990",
384 | type: "Android",
385 | os: "Android 11",
386 | },
387 | {
388 | manufacturer: "Huawei",
389 | model: "P40 Pro",
390 | cpu: "Kirin 990",
391 | type: "Android",
392 | os: "Android 10",
393 | },
394 | {
395 | manufacturer: "Xiaomi",
396 | model: "Redmi Note 10 Pro",
397 | cpu: "Qualcomm Snapdragon 732G",
398 | type: "Android",
399 | os: "Android 11",
400 | },
401 | {
402 | manufacturer: "Asus",
403 | model: "ROG Phone 5",
404 | cpu: "Qualcomm Snapdragon 888",
405 | type: "Android",
406 | os: "Android 11",
407 | },
408 | {
409 | manufacturer: "Dell",
410 | model: "XPS 17",
411 | cpu: "Intel Core i9-11980HK",
412 | type: "Laptop",
413 | os: "Windows 10",
414 | },
415 | {
416 | manufacturer: "HP",
417 | model: "Omen 15",
418 | cpu: "Intel Core i7-10750H",
419 | type: "Laptop",
420 | os: "Windows 10",
421 | },
422 | {
423 | manufacturer: "Lenovo",
424 | model: "Legion 5 Pro",
425 | cpu: "AMD Ryzen 7 5800H",
426 | type: "Laptop",
427 | os: "Windows 10",
428 | },
429 | {
430 | manufacturer: "Asus",
431 | model: "ZenBook Flip 14",
432 | cpu: "Intel Core i7-1165G7",
433 | type: "Laptop",
434 | os: "Windows 10",
435 | },
436 | {
437 | manufacturer: "Acer",
438 | model: "Aspire 5",
439 | cpu: "Intel Core i5-1135G7",
440 | type: "Laptop",
441 | os: "Windows 10",
442 | },
443 | {
444 | manufacturer: "Microsoft",
445 | model: "Surface Laptop Go",
446 | cpu: "Intel Core i5-1035G1",
447 | type: "Laptop",
448 | os: "Windows 10",
449 | },
450 | {
451 | manufacturer: "Razer",
452 | model: "Blade 17",
453 | cpu: "Intel Core i9-11900H",
454 | type: "Laptop",
455 | os: "Windows 10",
456 | },
457 | {
458 | manufacturer: "Sony",
459 | model: "VAIO SX14",
460 | cpu: "Intel Core i7-1065G7",
461 | type: "Laptop",
462 | os: "Windows 10",
463 | },
464 | {
465 | manufacturer: "Huawei",
466 | model: "MateBook X Pro",
467 | cpu: "Intel Core i5-10210U",
468 | type: "Laptop",
469 | os: "Windows 10",
470 | },
471 | {
472 | manufacturer: "Xiaomi",
473 | model: "Mi 10T Pro",
474 | cpu: "Qualcomm Snapdragon 865",
475 | type: "Android",
476 | os: "Android 10",
477 | },
478 | {
479 | manufacturer: "OnePlus",
480 | model: "OnePlus 8T",
481 | cpu: "Qualcomm Snapdragon 865",
482 | type: "Android",
483 | os: "Android 11",
484 | },
485 | {
486 | manufacturer: "Nokia",
487 | model: "Nokia 9 PureView",
488 | cpu: "Qualcomm Snapdragon 845",
489 | type: "Android",
490 | os: "Android 9",
491 | },
492 | {
493 | manufacturer: "Motorola",
494 | model: "Moto G60",
495 | cpu: "Qualcomm Snapdragon 732G",
496 | type: "Android",
497 | os: "Android 11",
498 | },
499 | {
500 | manufacturer: "LG",
501 | model: "Wing",
502 | cpu: "Qualcomm Snapdragon 765G",
503 | type: "Android",
504 | os: "Android 10",
505 | },
506 | {
507 | manufacturer: "Google",
508 | model: "Pixel 4 XL",
509 | cpu: "Qualcomm Snapdragon 855",
510 | type: "Android",
511 | os: "Android 10",
512 | },
513 | {
514 | manufacturer: "Apple",
515 | model: "iPhone XR",
516 | cpu: "A12 Bionic",
517 | type: "iPhone",
518 | os: "iOS 13",
519 | },
520 | {
521 | manufacturer: "Apple",
522 | model: "iPhone X",
523 | cpu: "A11 Bionic",
524 | type: "iPhone",
525 | os: "iOS 12",
526 | },
527 | ];
528 | module.exports = devices;
529 |
--------------------------------------------------------------------------------
/bot/config/userAgents.js:
--------------------------------------------------------------------------------
1 | const user_agents = [
2 | //Samsung Galaxy S22 5G
3 | "Mozilla/5.0 (Linux; Android 13; SM-S901B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
4 | "Mozilla/5.0 (Linux; Android 13; SM-S901U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
5 |
6 | //Samsung Galaxy S22 Ultra 5G
7 | "Mozilla/5.0 (Linux; Android 13; SM-S908B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
8 | "Mozilla/5.0 (Linux; Android 13; SM-S908U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Mobile Safari/537.36",
9 |
10 | //Samsung Galaxy S21 5G
11 | "Mozilla/5.0 (Linux; Android 13; SM-G991B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
12 | "Mozilla/5.0 (Linux; Android 13; SM-G991U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
13 |
14 | //Samsung Galaxy S21 Ultra 5G
15 | "Mozilla/5.0 (Linux; Android 13; SM-G998B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
16 | "Mozilla/5.0 (Linux; Android 13; SM-G998U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
17 |
18 | //Samsung Galaxy A53 5G
19 | "Mozilla/5.0 (Linux; Android 13; SM-A536B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
20 | "Mozilla/5.0 (Linux; Android 13; SM-A536U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
21 |
22 | //Samsung Galaxy A51
23 | "Mozilla/5.0 (Linux; Android 13; SM-A515F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
24 | "Mozilla/5.0 (Linux; Android 13; SM-A515U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
25 |
26 | //Samsung Galaxy S10
27 | "Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
28 | "Mozilla/5.0 (Linux; Android 12; SM-G973U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
29 |
30 | //Google Pixel 6
31 | "Mozilla/5.0 (Linux; Android 13; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
32 |
33 | //Google Pixel 6a
34 | "Mozilla/5.0 (Linux; Android 13; Pixel 6a) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
35 |
36 | //Google Pixel 6 Pro
37 | "Mozilla/5.0 (Linux; Android 13; Pixel 6 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
38 |
39 | //Google Pixel 7
40 | "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
41 |
42 | //Google Pixel 7 Pro
43 | "Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
44 |
45 | //Motorola Moto G Pure
46 | "Mozilla/5.0 (Linux; Android 12; moto g pure) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
47 |
48 | //Motorola Moto G Stylus 5G
49 | "Mozilla/5.0 (Linux; Android 12; moto g stylus 5G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
50 |
51 | //Motorola Moto G Stylus 5G (2022)
52 | "Mozilla/5.0 (Linux; Android 12; moto g stylus 5G (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
53 |
54 | //Motorola Moto G 5G (2022)
55 | "Mozilla/5.0 (Linux; Android 12; moto g 5G (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
56 |
57 | //Motorola Moto G Power (2022)
58 | "Mozilla/5.0 (Linux; Android 12; moto g power (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
59 |
60 | //Motorola Moto G Power (2021)
61 | "Mozilla/5.0 (Linux; Android 11; moto g power (2021)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
62 |
63 | //Redmi Note 9 Pro
64 | "Mozilla/5.0 (Linux; Android 12; Redmi Note 9 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
65 |
66 | //Redmi Note 8 Pro
67 | "Mozilla/5.0 (Linux; Android 11; Redmi Note 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
68 |
69 | //Huawei P30 Pro
70 | "Mozilla/5.0 (Linux; Android 10; VOG-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
71 |
72 | //Huawei P30 lite
73 | "Mozilla/5.0 (Linux; Android 10; MAR-LX1A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
74 |
75 | //Redmi Note 10 Pro
76 | "Mozilla/5.0 (Linux; Android 13; M2101K6G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
77 |
78 | //Xiaomi Poco X3 Pro
79 | "Mozilla/5.0 (Linux; Android 12; M2102J20SG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
80 |
81 | //Redmi Note 11 Pro 5G
82 | "Mozilla/5.0 (Linux; Android 12; 2201116SG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
83 |
84 | //OnePlus Nord N200 5G
85 | "Mozilla/5.0 (Linux; Android 12; DE2118) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
86 |
87 | //Apple iPhone SE (3rd generation)
88 | "Mozilla/5.0 (iPhone14,6; U; CPU iPhone OS 15_4 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/19E241 Safari/602.1",
89 |
90 | //iPhone 13 Pro Max
91 | "Mozilla/5.0 (iPhone14,3; U; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/19A346 Safari/602.1",
92 |
93 | //iPhone 12
94 | "Mozilla/5.0 (iPhone13,2; U; CPU iPhone OS 14_0like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/15E148 Safari/602.1",
95 |
96 | //iPhone 11
97 | "Mozilla/5.0 (iPhone12,1; U; CPU iPhone OS 13_0 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/15E148 Safari/602.1",
98 |
99 | //Apple iPhone XR (Safari)
100 | "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1",
101 |
102 | //Apple iPhone XS (Chrome)
103 | "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/69.0.3497.105 Mobile/15E148 Safari/605.1",
104 |
105 | //Apple iPhone XS Max (Firefox)
106 | "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/13.2b11866 Mobile/16A366 Safari/605.1.15",
107 |
108 | //Apple iPhone X
109 | "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1",
110 |
111 | //Apple iPhone 8
112 | "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1",
113 |
114 | //Apple iPhone 8 Plus
115 | "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1",
116 |
117 | //Apple iPhone 7
118 | "Mozilla/5.0 (iPhone9,3; U; CPU iPhone OS 10_0_1 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/14A403 Safari/602.1",
119 |
120 | //Apple iPhone 7 Plus
121 | "Mozilla/5.0 (iPhone9,4; U; CPU iPhone OS 10_0_1 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/14A403 Safari/602.1",
122 |
123 | //Apple iPhone 6
124 | "Mozilla/5.0 (Apple-iPhone7C2/1202.466; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543 Safari/419.3",
125 |
126 | //Samsung Galaxy S23 Ultra 5G
127 | "Mozilla/5.0 (Linux; Android 13; SM-S918B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
128 | "Mozilla/5.0 (Linux; Android 13; SM-S918U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
129 |
130 | //Samsung Galaxy S23 5G
131 | "Mozilla/5.0 (Linux; Android 13; SM-S911B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
132 | "Mozilla/5.0 (Linux; Android 13; SM-S911U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
133 |
134 | //Samsung Galaxy Note 20 Ultra 5G
135 | "Mozilla/5.0 (Linux; Android 13; SM-N986B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
136 | "Mozilla/5.0 (Linux; Android 13; SM-N986U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
137 |
138 | //Samsung Galaxy Note 20 5G
139 | "Mozilla/5.0 (Linux; Android 13; SM-N981B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
140 | "Mozilla/5.0 (Linux; Android 13; SM-N981U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
141 |
142 | //OnePlus 9 Pro
143 | "Mozilla/5.0 (Linux; Android 13; LE2121) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
144 | "Mozilla/5.0 (Linux; Android 13; LE2125) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
145 |
146 | //OnePlus 9
147 | "Mozilla/5.0 (Linux; Android 13; LE2113) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
148 | "Mozilla/5.0 (Linux; Android 13; LE2115) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
149 |
150 | //OnePlus 8T
151 | "Mozilla/5.0 (Linux; Android 13; KB2001) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
152 | "Mozilla/5.0 (Linux; Android 13; KB2005) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
153 |
154 | //Huawei P40 Pro
155 | "Mozilla/5.0 (Linux; Android 10; ELS-NX9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
156 | "Mozilla/5.0 (Linux; Android 10; ELS-N04) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
157 |
158 | //Huawei P40
159 | "Mozilla/5.0 (Linux; Android 10; ANA-NX9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
160 | "Mozilla/5.0 (Linux; Android 10; ANA-N29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
161 |
162 | //Xiaomi Mi 11
163 | "Mozilla/5.0 (Linux; Android 13; M2011K2C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
164 | "Mozilla/5.0 (Linux; Android 13; M2011K2G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
165 |
166 | //Xiaomi Mi 11 Ultra
167 | "Mozilla/5.0 (Linux; Android 13; M2102K1C) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
168 | "Mozilla/5.0 (Linux; Android 13; M2102K1G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
169 |
170 | //Xiaomi Mi 11i
171 | "Mozilla/5.0 (Linux; Android 13; M2012K11G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
172 |
173 | //Oppo Find X5 Pro
174 | "Mozilla/5.0 (Linux; Android 13; CPH2305) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
175 | "Mozilla/5.0 (Linux; Android 13; CPH2307) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
176 |
177 | //Oppo Find X3 Pro
178 | "Mozilla/5.0 (Linux; Android 13; CPH2173) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
179 |
180 | //Oppo Reno 6 Pro 5G
181 | "Mozilla/5.0 (Linux; Android 13; CPH2247) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
182 |
183 | //Vivo X70 Pro+
184 | "Mozilla/5.0 (Linux; Android 13; V2114) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
185 |
186 | //Vivo X60 Pro+
187 | "Mozilla/5.0 (Linux; Android 13; V2056A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
188 |
189 | //LG Velvet 5G
190 | "Mozilla/5.0 (Linux; Android 13; LM-G900N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
191 |
192 | //Sony Xperia 1 III
193 | "Mozilla/5.0 (Linux; Android 13; XQ-BC72) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
194 |
195 | //Sony Xperia 5 II
196 | "Mozilla/5.0 (Linux; Android 13; XQ-AS72) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
197 |
198 | //Nokia 8.3 5G
199 | "Mozilla/5.0 (Linux; Android 13; Nokia 8.3 5G) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
200 |
201 | //Nokia 7.2
202 | "Mozilla/5.0 (Linux; Android 12; Nokia 7.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
203 |
204 | //Realme GT 2 Pro
205 | "Mozilla/5.0 (Linux; Android 13; RMX3301) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
206 |
207 | //Realme X7 Pro
208 | "Mozilla/5.0 (Linux; Android 13; RMX2121) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
209 |
210 | //Asus ROG Phone 5
211 | "Mozilla/5.0 (Linux; Android 13; ASUS_I005DA) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
212 |
213 | //Asus Zenfone 8
214 | "Mozilla/5.0 (Linux; Android 13; ASUS_I006DA) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
215 |
216 | //Google Pixel 7 Pro
217 | "Mozilla/5.0 (Linux; Android 13; Pixel 7 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
218 |
219 | //Google Pixel 7
220 | "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
221 |
222 | //Google Pixel 6 Pro
223 | "Mozilla/5.0 (Linux; Android 13; Pixel 6 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
224 |
225 | //Google Pixel 6
226 | "Mozilla/5.0 (Linux; Android 13; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
227 |
228 | //Motorola Moto G Power (2022)
229 | "Mozilla/5.0 (Linux; Android 12; moto g power (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
230 |
231 | //Motorola Moto G Stylus (2022)
232 | "Mozilla/5.0 (Linux; Android 12; moto g stylus (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
233 |
234 | //ZTE Axon 30 Ultra
235 | "Mozilla/5.0 (Linux; Android 13; A2022U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
236 |
237 | //ZTE Nubia Red Magic 7 Pro
238 | "Mozilla/5.0 (Linux; Android 13; NX709J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36",
239 | //Apple iPad
240 | "Mozilla/5.0 (iPad; CPU OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1",
241 | "Mozilla/5.0 (iPad; CPU OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Mobile/15E148 Safari/604.1",
242 | "Mozilla/5.0 (iPad; CPU OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.4 Mobile/15E148 Safari/604.1",
243 | "Mozilla/5.0 (iPad; CPU OS 12_4_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1 Mobile/15E148 Safari/604.1",
244 | "Mozilla/5.0 (iPad; CPU OS 11_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1",
245 | //Samsung Galaxy Tab
246 | "Mozilla/5.0 (Linux; Android 12; SM-T970) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.104 Safari/537.36",
247 | "Mozilla/5.0 (Linux; Android 11; SM-T860) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.104 Safari/537.36",
248 | "Mozilla/5.0 (Linux; Android 10; SM-T510) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.104 Safari/537.36",
249 | "Mozilla/5.0 (Linux; Android 9; SM-T720) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.104 Safari/537.36",
250 | "Mozilla/5.0 (Linux; Android 8.1.0; SM-T580) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.104 Safari/537.36",
251 | ];
252 |
253 | module.exports = user_agents;
254 |
--------------------------------------------------------------------------------
/bot/core/api.js:
--------------------------------------------------------------------------------
1 | const app = require("../config/app");
2 | const logger = require("../utils/logger");
3 | const sleep = require("../utils/sleep");
4 | const _ = require("lodash");
5 |
6 | class ApiRequest {
7 | constructor(session_name, bot_name) {
8 | this.bot_name = bot_name;
9 | this.session_name = session_name;
10 | }
11 |
12 | async get_user_data(http_client) {
13 | try {
14 | const response = await http_client.post(
15 | `${app.apiUrl}/api/v1/account/start`
16 | );
17 | return response.data;
18 | } catch (error) {
19 | if (error?.response?.status >= 500 && error?.response?.status < 600) {
20 | return false;
21 | }
22 | if (error?.response?.data?.message) {
23 | logger.error(
24 | `[${this.bot_name}] | ${this.session_name} | Error while getting User Data: ${error?.response?.data?.message}`
25 | );
26 | } else {
27 | const regex = /ENOTFOUND\s([^\s]+)/;
28 | const match = error.message.match(regex);
29 | logger.error(
30 | `[${this.bot_name}] | ${
31 | this.session_name
32 | } | Error while getting User Data: ${
33 | error.message.includes("ENOTFOUND") ||
34 | error.message.includes("getaddrinfo") ||
35 | error.message.includes("ECONNREFUSED")
36 | ? `The proxy server at ${
37 | match && match[1] ? match[1] : "unknown address"
38 | } could not be found. Please check the proxy address and your network connection`
39 | : error.message
40 | }`
41 | );
42 | }
43 | await sleep(3); // Sleep for 3 seconds
44 | return null;
45 | }
46 | }
47 |
48 | async #validate_query_id(http_client) {
49 | try {
50 | const response = await http_client.post(
51 | `${app.apiUrl}/api/v1/account/start`
52 | );
53 | if (!_.isEmpty(response?.data)) {
54 | return true;
55 | }
56 | return false;
57 | } catch (error) {
58 | if (error?.response?.status >= 500 && error?.response?.status < 600) {
59 | return "server_error";
60 | }
61 | if (
62 | error?.response?.data?.message
63 | ?.toLowerCase()
64 | ?.includes("sign is missing") ||
65 | error?.response?.status == 401
66 | ) {
67 | return false;
68 | }
69 |
70 | throw error;
71 | }
72 | }
73 |
74 | async validate(http_client) {
75 | let validated = "server_error";
76 | while (typeof validated === "string" && validated === "server_error") {
77 | validated = await this.#validate_query_id(http_client);
78 |
79 | if (validated === "server_error") {
80 | logger.warning(
81 | `[${this.bot_name}] | ${this.session_name} | Server error. Retrying...`
82 | );
83 | await sleep(5);
84 | continue;
85 | }
86 |
87 | if (validated === false) {
88 | return false;
89 | }
90 |
91 | return true;
92 | }
93 | }
94 |
95 | async init_account(http_client) {
96 | const genders = ["male", "female"];
97 | const random = _.random(0, 1);
98 | try {
99 | const data = {
100 | lang: "en",
101 | sex: genders[random],
102 | };
103 | const response = await http_client.post(
104 | `${app.apiUrl}/api/v1/account/init`,
105 | JSON.stringify(data)
106 | );
107 | return response.data;
108 | } catch (error) {
109 | if (error?.response?.data?.message) {
110 | logger.warning(
111 | `[${this.bot_name}] | ${this.session_name} | Error while initting account: ${error?.response?.data?.message}`
112 | );
113 | } else {
114 | logger.error(
115 | `[${this.bot_name}] | ${this.session_name} | Error while initting account: ${error.message}`
116 | );
117 | }
118 | }
119 | }
120 |
121 | async sponsor(http_client) {
122 | try {
123 | const sponsors = [
124 | "binance",
125 | "okx",
126 | "bybit",
127 | "solana",
128 | "arbitrum",
129 | "ton",
130 | "binance-chain",
131 | ];
132 | const random = _.random(0, 6);
133 | const data = {
134 | sponsor: sponsors[random],
135 | };
136 |
137 | const response = await http_client.post(
138 | `${app.apiUrl}/api/v1/account/sponsor`,
139 | JSON.stringify(data)
140 | );
141 | return response.data;
142 | } catch (error) {
143 | if (error?.response?.data?.message) {
144 | logger.warning(
145 | `[${this.bot_name}] | ${this.session_name} | Error while setting sponsor: ${error?.response?.data?.message}`
146 | );
147 | } else {
148 | logger.error(
149 | `[${this.bot_name}] | ${this.session_name} | Error while setting sponsor: ${error.message}`
150 | );
151 | }
152 | }
153 | }
154 |
155 | async config(http_client) {
156 | try {
157 | const response = await http_client.post(`${app.apiUrl}/api/v1/config`);
158 | return response.data;
159 | } catch (error) {
160 | if (error?.response?.data?.message) {
161 | logger.warning(
162 | `[${this.bot_name}] | ${this.session_name} | Error while getting config: ${error?.response?.data?.message}`
163 | );
164 | } else {
165 | logger.error(
166 | `[${this.bot_name}] | ${this.session_name} | Error while getting config: ${error.message}`
167 | );
168 | }
169 | }
170 | }
171 |
172 | async get_daily_sync_info(http_client) {
173 | try {
174 | const response = await http_client.post(
175 | `${app.apiUrl}/api/v1/mine/sync/daily`
176 | );
177 | return response.data;
178 | } catch (error) {
179 | if (error?.response?.data?.message) {
180 | logger.warning(
181 | `[${this.bot_name}] | ${this.session_name} | Error while getting daily sync info: ${error?.response?.data?.message}`
182 | );
183 | } else {
184 | logger.error(
185 | `[${this.bot_name}] | ${this.session_name} | Error while getting daily sync info: ${error.message}`
186 | );
187 | }
188 | }
189 | }
190 |
191 | // start here tomorrow
192 | async tasks(http_client) {
193 | try {
194 | const response = await http_client.post(`${app.apiUrl}/api/v1/task/list`);
195 | return response.data;
196 | } catch (error) {
197 | if (error?.response?.data?.message) {
198 | logger.warning(
199 | `[${this.bot_name}] | ${this.session_name} | Error while getting tasks: ${error?.response?.data?.message}`
200 | );
201 | } else {
202 | logger.error(
203 | `[${this.bot_name}] | ${this.session_name} | Error while getting tasks: ${error.message}`
204 | );
205 | }
206 | }
207 | }
208 |
209 | async play_enigma(http_client, data) {
210 | try {
211 | const response = await http_client.post(
212 | `${app.apiUrl}/api/v1/mine/enigma`,
213 | JSON.stringify(data)
214 | );
215 | return response.data;
216 | } catch (error) {
217 | if (error?.response?.data?.message) {
218 | logger.warning(
219 | `[${this.bot_name}] | ${this.session_name} | Error while playing enigma: ${error?.response?.data?.message}`
220 | );
221 | } else {
222 | logger.error(
223 | `[${this.bot_name}] | ${this.session_name} | Error while playing enigma: ${error.message}`
224 | );
225 | }
226 | }
227 | }
228 |
229 | async play_combo(http_client, data) {
230 | try {
231 | const response = await http_client.post(
232 | `${app.apiUrl}/api/v1/mine/combo`,
233 | JSON.stringify(data)
234 | );
235 | return response.data;
236 | } catch (error) {
237 | if (error?.response?.data?.message) {
238 | logger.warning(
239 | `[${this.bot_name}] | ${this.session_name} | Error while playing combo ${error?.response?.data?.message}`
240 | );
241 | } else {
242 | logger.error(
243 | `[${this.bot_name}] | ${this.session_name} | Error while playing combo: ${error.message}`
244 | );
245 | }
246 | }
247 | }
248 |
249 | async play_easter(http_client, data) {
250 | try {
251 | const response = await http_client.post(
252 | `${app.apiUrl}/api/v1/mine/easter-eggs`,
253 | JSON.stringify(data)
254 | );
255 | return response.data;
256 | } catch (error) {
257 | if (error?.response?.data?.message) {
258 | logger.warning(
259 | `[${this.bot_name}] | ${this.session_name} | Error while playing easter egg: ${error?.response?.data?.message}`
260 | );
261 | } else {
262 | logger.error(
263 | `[${this.bot_name}] | ${this.session_name} | Error while playing easter egg: ${error.message}`
264 | );
265 | }
266 | }
267 | }
268 |
269 | async get_boosts(http_client) {
270 | try {
271 | const response = await http_client.post(
272 | `${app.apiUrl}/api/v1/boosts/list`
273 | );
274 | return response.data;
275 | } catch (error) {
276 | if (error?.response?.data?.message) {
277 | logger.warning(
278 | `[${this.bot_name}] | ${this.session_name} | Error while getting boosts: ${error?.response?.data?.message}`
279 | );
280 | } else {
281 | logger.error(
282 | `[${this.bot_name}] | ${this.session_name} | Error while getting boosts: ${error.message}`
283 | );
284 | }
285 | }
286 | }
287 |
288 | async upgrade_boost(http_client, data) {
289 | try {
290 | const response = await http_client.post(
291 | `${app.apiUrl}/api/v1/boosts`,
292 | JSON.stringify(data)
293 | );
294 | return response.data;
295 | } catch (error) {
296 | if (
297 | error?.response?.data?.message &&
298 | error?.response?.data?.message.includes("not available")
299 | ) {
300 | return "not_available";
301 | }
302 |
303 | if (
304 | error?.response?.data?.message &&
305 | error?.response?.data?.message.includes("exceeded")
306 | ) {
307 | return "exceeded";
308 | }
309 |
310 | if (error?.response?.data?.message) {
311 | logger.warning(
312 | `[${this.bot_name}] | ${this.session_name} | Error while upgrading boosts ${error?.response?.data?.message}`
313 | );
314 | } else {
315 | logger.error(
316 | `[${this.bot_name}] | ${this.session_name} | Error while upgrading boosts: ${error.message}`
317 | );
318 | }
319 | }
320 | }
321 |
322 | async claim_task(http_client, data) {
323 | try {
324 | const response = await http_client.post(
325 | `${app.apiUrl}/api/v1/task/upgrade`,
326 | JSON.stringify(data)
327 | );
328 | return response.data;
329 | } catch (error) {
330 | if (error?.response?.data?.message) {
331 | logger.warning(
332 | `[${this.bot_name}] | ${this.session_name} | Error while claiming task ${error?.response?.data?.message}`
333 | );
334 | } else {
335 | logger.error(
336 | `[${this.bot_name}] | ${this.session_name} | Error while claiming task: ${error.message}`
337 | );
338 | }
339 | }
340 | }
341 |
342 | async upgrade_cards(http_client, data) {
343 | try {
344 | const response = await http_client.post(
345 | `${app.apiUrl}/api/v1/mine/upgrade`,
346 | JSON.stringify(data)
347 | );
348 | return response.data;
349 | } catch (error) {
350 | if (
351 | error?.response?.data?.message &&
352 | error?.response?.data?.message.includes("insufficient")
353 | ) {
354 | return "insufficient";
355 | } else if (error?.response?.data?.message) {
356 | logger.warning(
357 | `[${this.bot_name}] | ${this.session_name} | Error while upgrading cards ${error?.response?.data?.message}`
358 | );
359 | } else {
360 | logger.error(
361 | `[${this.bot_name}] | ${this.session_name} | Error while upgrading cards: ${error.message}`
362 | );
363 | }
364 | }
365 | }
366 |
367 | async taps(http_client, data) {
368 | try {
369 | const response = await http_client.post(
370 | `${app.apiUrl}/api/v1/clicker/tap`,
371 | JSON.stringify(data)
372 | );
373 | return response.data;
374 | } catch (error) {
375 | if (error?.response?.data?.message) {
376 | logger.warning(
377 | `[${this.bot_name}] | ${this.session_name} | Error while tapping ${error?.response?.data?.message}`
378 | );
379 | } else {
380 | logger.error(
381 | `[${this.bot_name}] | ${this.session_name} | Error while tapping: ${error.message}`
382 | );
383 | }
384 | }
385 | }
386 |
387 | async daily_reward(http_client) {
388 | try {
389 | const response = await http_client.post(
390 | `${app.apiUrl}/api/v1/task/upgrade`,
391 | JSON.stringify({
392 | taskId: "streak_days_reward",
393 | timezone: "Africa/Accra",
394 | })
395 | );
396 | return response.data;
397 | } catch (error) {
398 | if (
399 | error?.response?.data?.message &&
400 | error?.response?.data?.message.includes(
401 | "you_are_not_subscribe_to_channel"
402 | )
403 | ) {
404 | return "not_subscribed";
405 | } else if (
406 | error?.response?.data?.message &&
407 | error?.response?.data?.message.includes("comeback")
408 | ) {
409 | return "claimed";
410 | } else if (error?.response?.data?.message) {
411 | logger.warning(
412 | `[${this.bot_name}] | ${this.session_name} | Error while claiming daily reward ${error?.response?.data?.message}`
413 | );
414 | return "claimed";
415 | } else {
416 | logger.error(
417 | `[${this.bot_name}] | ${this.session_name} | Error while claiming daily reward: ${error.message}`
418 | );
419 | return null;
420 | }
421 | }
422 | }
423 |
424 | async get_combo_data(http_client) {
425 | try {
426 | const response = await http_client.get(`${app.comboApi}`);
427 | return response.data;
428 | } catch (error) {
429 | if (error?.response?.data?.message) {
430 | logger.warning(
431 | `[${this.bot_name}] | ${this.session_name} | Error while tapping ${error?.response?.data?.message}`
432 | );
433 | } else {
434 | logger.error(
435 | `[${this.bot_name}] | ${this.session_name} | Error while tapping: ${error.message}`
436 | );
437 | }
438 | }
439 | }
440 |
441 | async mine_sync(http_client) {
442 | try {
443 | const response = await http_client.post(`${app.apiUrl}/api/v1/mine/sync`);
444 | return response.data;
445 | } catch (error) {
446 | if (error?.response?.data?.message) {
447 | logger.warning(
448 | `[${this.bot_name}] | ${this.session_name} | Error while getting mine sync ${error?.response?.data?.message}`
449 | );
450 | } else {
451 | logger.error(
452 | `[${this.bot_name}] | ${this.session_name} | Error while getting mine sync: ${error.message}`
453 | );
454 | }
455 | }
456 | }
457 | }
458 |
459 | module.exports = ApiRequest;
460 |
--------------------------------------------------------------------------------
/bot/core/nonSessionTapper.js:
--------------------------------------------------------------------------------
1 | const logger = require("../utils/logger");
2 | const headers = require("./header");
3 | const settings = require("../config/config");
4 | const app = require("../config/app");
5 | const user_agents = require("../config/userAgents");
6 | const fs = require("fs");
7 | const sleep = require("../utils/sleep");
8 | const ApiRequest = require("./api");
9 | const _ = require("lodash");
10 | const moment = require("moment");
11 | const filterArray = require("../helpers/filterArray");
12 | const upgradeTabCardsBuying = require("../scripts/upgradeTabCardsBuying");
13 | const upgradeNoConditionCards = require("../scripts/upgradeNoConditionCards");
14 | const path = require("path");
15 | const _isArray = require("../utils/_isArray");
16 | const fdy = require("fdy-scraping");
17 |
18 | class NonSessionTapper {
19 | constructor(query_id, query_name) {
20 | this.bot_name = "rockyrabbit";
21 | this.session_name = query_name;
22 | this.query_id = query_id;
23 | this.API_URL = app.apiUrl;
24 | this.session_user_agents = this.#load_session_data();
25 | this.headers = { ...headers, "user-agent": this.#get_user_agent() };
26 | this.api = new ApiRequest(this.session_name, this.bot_name);
27 | }
28 |
29 | #load_session_data() {
30 | try {
31 | const filePath = path.join(process.cwd(), "session_user_agents.json");
32 | const data = fs.readFileSync(filePath, "utf8");
33 | return JSON.parse(data);
34 | } catch (error) {
35 | if (error.code === "ENOENT") {
36 | return {};
37 | } else {
38 | throw error;
39 | }
40 | }
41 | }
42 |
43 | #get_random_user_agent() {
44 | const randomIndex = Math.floor(Math.random() * user_agents.length);
45 | return user_agents[randomIndex];
46 | }
47 |
48 | #get_user_agent() {
49 | if (this.session_user_agents[this.session_name]) {
50 | return this.session_user_agents[this.session_name];
51 | }
52 |
53 | logger.info(
54 | `[${this.bot_name}] | ${this.session_name} | Generating new user agent...`
55 | );
56 | const newUserAgent = this.#get_random_user_agent();
57 | this.session_user_agents[this.session_name] = newUserAgent;
58 | this.#save_session_data(this.session_user_agents);
59 | return newUserAgent;
60 | }
61 |
62 | #save_session_data(session_user_agents) {
63 | const filePath = path.join(process.cwd(), "session_user_agents.json");
64 | fs.writeFileSync(filePath, JSON.stringify(session_user_agents, null, 2));
65 | }
66 |
67 | #get_boost_by_id(data, boostId) {
68 | const boost = data.boostsList.find((boost) => boost.boostId === boostId);
69 | return boost ? boost : {};
70 | }
71 |
72 | #get_platform(userAgent) {
73 | const platformPatterns = [
74 | { pattern: /iPhone/i, platform: "ios" },
75 | { pattern: /Android/i, platform: "android" },
76 | { pattern: /iPad/i, platform: "ios" },
77 | ];
78 |
79 | for (const { pattern, platform } of platformPatterns) {
80 | if (pattern.test(userAgent)) {
81 | return platform;
82 | }
83 | }
84 |
85 | return "Unknown";
86 | }
87 |
88 | async #check_proxy(http_client, proxy) {
89 | try {
90 | const response = await http_client.get("https://httpbin.org/ip");
91 | const ip = response.data.origin;
92 | logger.info(
93 | `[${this.bot_name}] | ${this.session_name} | Proxy IP: ${ip}`
94 | );
95 | } catch (error) {
96 | if (
97 | error.message.includes("ENOTFOUND") ||
98 | error.message.includes("getaddrinfo") ||
99 | error.message.includes("ECONNREFUSED")
100 | ) {
101 | logger.error(
102 | `[${this.bot_name}] | ${this.session_name} | Error: Unable to resolve the proxy address. The proxy server at ${proxy.ip}:${proxy.port} could not be found. Please check the proxy address and your network connection.`
103 | );
104 | logger.error(
105 | `[${this.bot_name}] | ${this.session_name} | No proxy will be used.`
106 | );
107 | } else {
108 | logger.error(
109 | `[${this.bot_name}] | ${this.session_name} | Proxy: ${proxy.ip}:${proxy.port} | Error: ${error.message}`
110 | );
111 | }
112 |
113 | return false;
114 | }
115 | }
116 |
117 | async #get_user_data(http_client) {
118 | let profile_data = false;
119 | while (typeof profile_data === "boolean" && !profile_data) {
120 | profile_data = await this.api.get_user_data(http_client);
121 | if (profile_data === false) {
122 | logger.warning(
123 | `[${this.bot_name}] | ${this.session_name} | Unable to get user data. Retrying...`
124 | );
125 | await sleep(5);
126 | continue;
127 | }
128 |
129 | if (_.isNull(profile_data) || _.isEmpty(profile_data)) {
130 | logger.warning(
131 | `[${this.bot_name}] | ${this.session_name} | Error while getting user data. Aborting...`
132 | );
133 | break;
134 | }
135 |
136 | return profile_data;
137 | }
138 | return null;
139 | }
140 |
141 | async run(proxy) {
142 | let http_client;
143 |
144 | let profile_data, boosts_list;
145 | let sleep_daily_reward = 0;
146 | let tasks_list = {};
147 | let config = {};
148 | let get_daily_sync_info = {};
149 | let mine_sync = [];
150 | let exceeded_energy = 0;
151 | let exceeded_turbo = 0;
152 | let sleep_empty_energy = 0;
153 |
154 | if (settings.USE_PROXY_FROM_FILE && proxy) {
155 | http_client = fdy.create({
156 | headers: this.headers,
157 | proxy,
158 | });
159 | const proxy_result = await this.#check_proxy(http_client, proxy);
160 | if (!proxy_result) {
161 | http_client = fdy.create({
162 | headers: this.headers,
163 | });
164 | }
165 | } else {
166 | http_client = fdy.create({
167 | headers: this.headers,
168 | });
169 | }
170 | while (true) {
171 | try {
172 | const currentTime = _.floor(Date.now() / 1000);
173 |
174 | http_client.defaults.headers["sec-ch-ua-platform"] = this.#get_platform(
175 | this.#get_user_agent()
176 | );
177 |
178 | const tg_web_data = await this.query_id;
179 |
180 | http_client.defaults.headers["authorization"] = `tma ${tg_web_data}`;
181 | await sleep(2);
182 | // Get profile data
183 | profile_data = await this.#get_user_data(http_client);
184 | boosts_list = await this.api.get_boosts(http_client);
185 | tasks_list = await this.api.tasks(http_client);
186 | config = await this.api.config(http_client);
187 | mine_sync = await this.api.mine_sync(http_client);
188 | get_daily_sync_info = await this.api.get_daily_sync_info(http_client);
189 |
190 | if (
191 | _.isEmpty(profile_data) ||
192 | profile_data?.status?.toLowerCase() !== "ok"
193 | ) {
194 | continue;
195 | }
196 |
197 | if (!profile_data?.initAccount || _.isEmpty(profile_data?.account)) {
198 | await this.api.init_account(http_client);
199 | await this.api.sponsor(http_client);
200 | continue;
201 | }
202 |
203 | if (profile_data?.account?.sponsor == "") {
204 | await this.api.sponsor(http_client);
205 | continue;
206 | }
207 |
208 | await sleep(1);
209 |
210 | if (profile_data?.clicker?.lastPassiveEarn > 0) {
211 | logger.info(
212 | `[${this.bot_name}] | ${this.session_name} | 💸 Last passive earn: +${profile_data?.clicker?.lastPassiveEarn} | Earn per hour: ${profile_data?.clicker?.earnPassivePerHour}`
213 | );
214 | }
215 |
216 | // Daily reward
217 | if (settings.AUTO_CLAIM_REWARD && sleep_daily_reward <= currentTime) {
218 | const reward_data = await this.api.daily_reward(http_client);
219 |
220 | if (
221 | typeof reward_data === "string" &&
222 | reward_data.includes("not_subscribed")
223 | ) {
224 | logger.info(
225 | `[${this.bot_name}] | ${this.session_name} |⌛Join RockyRabit channel before daily reward can be claim. Skipping daily reward claim...`
226 | );
227 | } else if (
228 | typeof reward_data === "string" &&
229 | reward_data.includes("claimed")
230 | ) {
231 | sleep_daily_reward =
232 | new Date(moment().add(1, "days").startOf("day")).getTime() / 1000;
233 | logger.info(
234 | `[${this.bot_name}] | ${this.session_name} | 🚶 Daily reward already claimed. Skipping...`
235 | );
236 | } else if (reward_data?.status?.toLowerCase() === "ok") {
237 | profile_data = await this.#get_user_data(http_client);
238 | logger.info(
239 | `[${this.bot_name}] | ${this.session_name} | 🎉 Claimed daily reward successfully | Reward: ${reward_data?.task?.rewardCoins}
| Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}
`
240 | );
241 | sleep_daily_reward =
242 | new Date(moment().add(1, "days").startOf("day")).getTime() / 1000;
243 | }
244 | }
245 |
246 | await sleep(1);
247 |
248 | //Send taps
249 | if (settings.RANDOM_TAPS_COUNT[0] > settings.RANDOM_TAPS_COUNT[1]) {
250 | logger.error(
251 | `[${this.bot_name}] | ${this.session_name} | ❗️Invalid Random Taps Count. RANDOM_TAPS_COUNT MIN must be less than RANDOM_TAPS_COUNT MAX. Example: RANDOM_TAPS_COUNT: [10, 20]`
252 | );
253 | process.exit(1);
254 | }
255 | if (
256 | !_.isInteger(settings.RANDOM_TAPS_COUNT[0]) ||
257 | !_.isInteger(settings.RANDOM_TAPS_COUNT[1])
258 | ) {
259 | logger.error(
260 | `[${this.bot_name}] | ${this.session_name} | ❗️Invalid Random Taps Count. RANDOM_TAPS_COUNT MIN and MAX must be integers/numbers. Example: RANDOM_TAPS_COUNT: [10, 20]`
261 | );
262 | process.exit(1);
263 | }
264 |
265 | let taps_sent_count = 0;
266 | if (sleep_empty_energy <= currentTime) {
267 | while (
268 | profile_data?.clicker?.availableTaps >
269 | settings.MIN_AVAILABLE_ENERGY &&
270 | taps_sent_count < 10
271 | ) {
272 | await sleep(_.random(5, 15));
273 | let taps = _.random(
274 | settings.RANDOM_TAPS_COUNT[0],
275 | settings.RANDOM_TAPS_COUNT[1]
276 | );
277 | boosts_list = await this.api.get_boosts(http_client);
278 | if (
279 | !moment(exceeded_turbo * 1000).isSame(new Date().getTime(), "day")
280 | ) {
281 | const turbo_data = this.#get_boost_by_id(boosts_list, "turbo");
282 |
283 | const turbo_boost = await this.api.upgrade_boost(http_client, {
284 | boostId: turbo_data?.boostId,
285 | timezone: app.timezone,
286 | });
287 |
288 | if (turbo_boost?.status?.toLowerCase() === "ok") {
289 | logger.info(
290 | `[${this.bot_name}] | ${this.session_name} | ⏩ Turbo boost activated.`
291 | );
292 | await sleep(5);
293 | } else if (
294 | typeof turbo_boost == "string" &&
295 | turbo_boost.includes("exceeded")
296 | ) {
297 | exceeded_turbo = currentTime;
298 | }
299 | }
300 |
301 | const taps_can_send =
302 | profile_data?.clicker?.availableTaps /
303 | profile_data?.clicker?.earnPerTap;
304 | const count =
305 | taps > _.floor(taps_can_send) ? _.floor(taps_can_send) : taps;
306 | const taps_result = await this.api.taps(http_client, { count });
307 |
308 | if (taps_result?.status?.toLowerCase() === "ok") {
309 | const balanceChange =
310 | taps_result?.clicker?.balance - profile_data?.clicker?.balance;
311 | profile_data = await this.#get_user_data(http_client);
312 | logger.info(
313 | `[${this.bot_name}] | ${this.session_name} | ✅ Taps sent successfully | Balance: ${profile_data?.clicker?.balance} (+${balanceChange}) | Total: ${profile_data?.clicker?.totalBalance}
| Available energy: ${profile_data?.clicker?.availableTaps}`
314 | );
315 | }
316 |
317 | profile_data = await this.#get_user_data(http_client);
318 | boosts_list = await this.api.get_boosts(http_client);
319 |
320 | if (
321 | profile_data?.clicker?.availableTaps <=
322 | settings.MIN_AVAILABLE_ENERGY
323 | ) {
324 | if (_.isEmpty(boosts_list)) {
325 | break;
326 | }
327 | const full_taps_data = this.#get_boost_by_id(
328 | boosts_list,
329 | "full-available-taps"
330 | );
331 | if (_.isEmpty(full_taps_data)) {
332 | break;
333 | }
334 |
335 | if (
336 | full_taps_data?.lastUpgradeAt + 3605 <= currentTime &&
337 | settings.APPLY_DAILY_FULL_ENERGY &&
338 | !moment(exceeded_energy * 1000).isSame(
339 | new Date().getTime(),
340 | "day"
341 | )
342 | ) {
343 | const full_energy_boost = await this.api.upgrade_boost(
344 | http_client,
345 | {
346 | boostId: full_taps_data?.boostId,
347 | timezone: app.timezone,
348 | }
349 | );
350 |
351 | if (
352 | typeof full_energy_boost == "string" &&
353 | full_energy_boost.includes("exceeded")
354 | ) {
355 | exceeded_energy = currentTime;
356 | break;
357 | }
358 |
359 | if (full_energy_boost?.status?.toLowerCase() === "ok") {
360 | profile_data = await this.#get_user_data(http_client);
361 | logger.info(
362 | `[${this.bot_name}] | ${this.session_name} | 🔋Full energy boost applied successfully`
363 | );
364 | }
365 | } else {
366 | profile_data = await this.#get_user_data(http_client);
367 | sleep_empty_energy = currentTime + settings.SLEEP_EMPTY_ENERGY;
368 |
369 | logger.info(
370 | `[${this.bot_name}] | ${
371 | this.session_name
372 | } | Not enough energy to send ${count} taps. Needed ${
373 | count * profile_data?.clicker?.earnPerTap
374 | } energy to send taps | Available: ${
375 | profile_data?.clicker?.availableTaps
376 | } | Sleeping ${settings.SLEEP_EMPTY_ENERGY}s`
377 | );
378 | break;
379 | }
380 | }
381 |
382 | taps_sent_count++;
383 | }
384 | }
385 |
386 | await sleep(2);
387 |
388 | // Daily combos
389 | const combo_data = await this.api.get_combo_data(http_client);
390 | if (!_.isEmpty(combo_data)) {
391 | const expireAtForCards =
392 | new Date(combo_data?.expireAtForCards).getTime() / 1000;
393 |
394 | const expireAtForEaster =
395 | new Date(combo_data?.expireAtForEaster).getTime() / 1000;
396 |
397 | if (
398 | settings.AUTO_PLAY_ENIGMA &&
399 | !_.isEmpty(combo_data?.enigma) &&
400 | !_.isEmpty(get_daily_sync_info)
401 | ) {
402 | const play_enigma_data = get_daily_sync_info?.enigma;
403 |
404 | if (
405 | play_enigma_data?.completedAt < 1 &&
406 | Array.isArray(combo_data?.enigma) &&
407 | play_enigma_data?.passphrase?.includes(combo_data?.enigma[0])
408 | ) {
409 | const play_enigma = await this.api.play_enigma(http_client, {
410 | passphrase: Array.isArray(combo_data?.enigma)
411 | ? combo_data.enigma.join(",")
412 | : combo_data.enigma,
413 | enigmaId: play_enigma_data?.enigmaId,
414 | });
415 |
416 | if (play_enigma?.status?.toLowerCase() === "ok") {
417 | profile_data = await this.#get_user_data(http_client);
418 | logger.info(
419 | `[${this.bot_name}] | ${this.session_name} | 🎊 Enigma claimed successfully | Reward: ${play_enigma_data?.amount} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}
`
420 | );
421 | }
422 | }
423 | }
424 |
425 | if (
426 | settings.AUTO_PLAY_COMBO &&
427 | !_.isEmpty(combo_data?.cards) &&
428 | !_.isEmpty(get_daily_sync_info)
429 | ) {
430 | const combo_info = get_daily_sync_info?.superSet;
431 |
432 | if (combo_info?.completedAt < 1 && expireAtForCards > currentTime) {
433 | const play_combo = await this.api.play_combo(http_client, {
434 | combos: Array.isArray(combo_data?.cards)
435 | ? combo_data?.cards.join(",")
436 | : combo_data?.cards,
437 | comboId: combo_info?.comboId,
438 | });
439 |
440 | if (play_combo?.status?.toLowerCase() === "ok") {
441 | profile_data = await this.#get_user_data(http_client);
442 | logger.info(
443 | `[${this.bot_name}] | ${this.session_name} | 🎊 Daily combo claimed successfully | Reward: ${play_combo?.winner?.rabbitWinner} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}
`
444 | );
445 | }
446 | }
447 | }
448 |
449 | if (
450 | settings.AUTO_CLAIM_EASTER_EGG &&
451 | !_.isEmpty(combo_data?.easter) &&
452 | !_.isEmpty(get_daily_sync_info?.easterEggs)
453 | ) {
454 | const easter_info = get_daily_sync_info?.easterEggs;
455 |
456 | if (
457 | easter_info?.completedAt < 1 &&
458 | expireAtForEaster > currentTime
459 | ) {
460 | const play_easter = await this.api.play_easter(http_client, {
461 | easter: combo_data?.easter,
462 | easterEggsId: easter_info?.easterEggsId,
463 | });
464 |
465 | if (play_easter?.status?.toLowerCase() === "ok") {
466 | profile_data = await this.#get_user_data(http_client);
467 | logger.info(
468 | `[${this.bot_name}] | ${this.session_name} | 🎊 Easter Egg claimed successfully | Reward: ${easter_info?.amount} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}
`
469 | );
470 | }
471 | }
472 | }
473 | }
474 |
475 | await sleep(3);
476 |
477 | // Boost upgrade (earn-per-tap)
478 | const tap_boost_data = this.#get_boost_by_id(
479 | boosts_list,
480 | "earn-per-tap"
481 | );
482 | if (
483 | settings.AUTO_UPGRADE_TAP &&
484 | !_.isEmpty(tap_boost_data) &&
485 | settings.MAX_TAP_LEVEL > tap_boost_data?.level &&
486 | tap_boost_data?.price <= profile_data?.clicker?.balance
487 | ) {
488 | const tap_boost = await this.api.upgrade_boost(http_client, {
489 | boostId: tap_boost_data?.boostId,
490 | timezone: app.timezone,
491 | });
492 |
493 | if (tap_boost?.status?.toLowerCase() === "ok") {
494 | profile_data = await this.#get_user_data(http_client);
495 | logger.info(
496 | `[${this.bot_name}] | ${this.session_name} | ⬆️ Tap upgraded successfully | Level: ${tap_boost_data?.level} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}
| Available energy: ${profile_data?.clicker?.availableTaps}`
497 | );
498 | }
499 | }
500 | await sleep(3);
501 |
502 | // Boost upgrade (max-taps)
503 | const energy_boost_data = this.#get_boost_by_id(
504 | boosts_list,
505 | "max-taps"
506 | );
507 |
508 | if (
509 | settings.AUTO_UPGRADE_ENERGY_LIMIT &&
510 | !_.isEmpty(energy_boost_data) &&
511 | settings.MAX_ENERGY_LIMIT_LEVEL > energy_boost_data?.level &&
512 | energy_boost_data?.price <= profile_data?.clicker?.balance
513 | ) {
514 | const energy_boost = await this.api.upgrade_boost(http_client, {
515 | boostId: energy_boost_data?.boostId,
516 | timezone: app.timezone,
517 | });
518 | if (energy_boost?.status?.toLowerCase() === "ok") {
519 | profile_data = await this.#get_user_data(http_client);
520 | logger.info(
521 | `[${this.bot_name}] | ${this.session_name} | ⬆️ Energy limit upgraded successfully | Level: ${energy_boost_data?.level} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}
| Available energy: ${profile_data?.clicker?.availableTaps}`
522 | );
523 | }
524 | }
525 |
526 | await sleep(3);
527 |
528 | // Boost upgrade (hourly-income-limit)
529 | const hourly_limit_data = this.#get_boost_by_id(
530 | boosts_list,
531 | "hourly-income-limit"
532 | );
533 |
534 | if (
535 | settings.AUTO_HOURLY_LIMIT &&
536 | !_.isEmpty(hourly_limit_data) &&
537 | settings.MAX_HOURLY_LIMIT_LEVEL > hourly_limit_data?.level &&
538 | hourly_limit_data?.price <= profile_data?.clicker?.balance
539 | ) {
540 | const hourly_limit = await this.api.upgrade_boost(http_client, {
541 | boostId: hourly_limit_data?.boostId,
542 | timezone: app.timezone,
543 | });
544 | if (hourly_limit?.status?.toLowerCase() === "ok") {
545 | profile_data = await this.#get_user_data(http_client);
546 | logger.info(
547 | `[${this.bot_name}] | ${this.session_name} | ⬆️ Hourly limit upgraded successfully | Level: ${hourly_limit_data?.level} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}
| Available energy: ${profile_data?.clicker?.availableTaps}`
548 | );
549 | }
550 | }
551 |
552 | if (settings.AUTO_COMPLETE_TASKS) {
553 | await sleep(2);
554 |
555 | if (!_.isEmpty(tasks_list) && !_.isEmpty(tasks_list.tasks)) {
556 | const uncompletedTasks = filterArray.getUncompletedTasks(
557 | tasks_list.tasks
558 | );
559 |
560 | if (!_.isEmpty(uncompletedTasks)) {
561 | for (const task of uncompletedTasks) {
562 | const complete_task = await this.api.claim_task(http_client, {
563 | taskId: task?.id,
564 | timezone: app.timezone,
565 | });
566 | if (complete_task?.status?.toLowerCase() === "ok") {
567 | logger.info(
568 | `[${this.bot_name}] | ${this.session_name} | ✔️ Task completed successfully | Task title: ${task?.name} | Reward: ${task?.rewardCoins}
`
569 | );
570 | } else {
571 | logger.error(
572 | `[${this.bot_name}] | ${this.session_name} | ✖️ Could not complete task | Task title: ${task?.name} | Reward: ${task?.rewardCoins}
`
573 | );
574 | }
575 | }
576 | }
577 | }
578 | }
579 |
580 | if (settings.AUTO_UPGRADE_CARD) {
581 | if (
582 | _.isEmpty(config?.config) ||
583 | _.isEmpty(config?.config?.upgrade) ||
584 | _.isEmpty(mine_sync)
585 | ) {
586 | continue;
587 | }
588 |
589 | const leagues = Array.from(
590 | { length: 10 },
591 | (_, i) => filterArray.getById(mine_sync, `league_${i + 1}`)[0]
592 | );
593 |
594 | if (leagues.some((league) => _.isEmpty(league))) {
595 | continue;
596 | }
597 |
598 | const cards_fighter = filterArray.getCardsOnUpgradeTab(
599 | config?.config?.upgrade,
600 | "fighter",
601 | "upgrade"
602 | );
603 | const cards_coach = filterArray.getCardsOnUpgradeTab(
604 | config?.config?.upgrade,
605 | "coach",
606 | "upgrade"
607 | );
608 |
609 | if (_.isEmpty(cards_fighter) || _.isEmpty(cards_coach)) {
610 | continue;
611 | }
612 |
613 | for (let i = 0; i < leagues.length; i++) {
614 | const allPreviousLeaguesCompleted =
615 | i === 0 ||
616 | leagues
617 | .slice(0, i)
618 | .every((league) => league?.isCompleted === true);
619 |
620 | if (
621 | leagues[i]?.isCompleted === false &&
622 | allPreviousLeaguesCompleted
623 | ) {
624 | const level = i + 1;
625 | const cards_fighter_level = filterArray.getCardsWithLevel(
626 | mine_sync,
627 | cards_fighter,
628 | level
629 | );
630 | const cards_coach_level = filterArray.getCardsWithLevel(
631 | mine_sync,
632 | cards_coach,
633 | level
634 | );
635 |
636 | if (!_.isEmpty(cards_fighter_level)) {
637 | await upgradeTabCardsBuying(
638 | cards_fighter_level,
639 | http_client,
640 | this.api,
641 | this.session_name,
642 | this.bot_name
643 | );
644 | mine_sync = await this.api.mine_sync(http_client);
645 | continue;
646 | } else if (!_.isEmpty(cards_coach_level)) {
647 | await upgradeTabCardsBuying(
648 | cards_coach_level,
649 | http_client,
650 | this.api,
651 | this.session_name,
652 | this.bot_name
653 | );
654 | mine_sync = await this.api.mine_sync(http_client);
655 | continue;
656 | }
657 |
658 | if (leagues[i]?.price <= profile_data?.clicker?.balance) {
659 | const upgrade_league = await this.api.upgrade_cards(
660 | http_client,
661 | {
662 | upgradeId: `league_${level}`,
663 | }
664 | );
665 |
666 | if (upgrade_league?.status?.toLowerCase() === "ok") {
667 | profile_data = await this.#get_user_data(http_client);
668 |
669 | logger.info(
670 | `[${this.bot_name}] | ${this.session_name} | ⬆️ League_${level} upgraded successfully | Level: ${leagues[i]?.level} | Cost: ${leagues[i]?.price} | Balance: ${profile_data?.clicker?.balance}`
671 | );
672 | }
673 | } else {
674 | logger.info(
675 | `[${this.bot_name}] | ${this.session_name} | 👎 Not enough balance to upgrade league ${level} | Need: ${leagues[i]?.price} | Balance: ${profile_data?.clicker?.balance}
`
676 | );
677 | continue;
678 | }
679 | }
680 | }
681 |
682 | await sleep(2);
683 |
684 | // get cards with no conditions
685 | const cards_wnc = filterArray.getEmptyConditions(
686 | config?.config?.upgrade
687 | );
688 |
689 | await upgradeNoConditionCards(
690 | cards_wnc,
691 | this.api,
692 | http_client,
693 | this.session_name,
694 | this.bot_name
695 | );
696 | }
697 | } catch (error) {
698 | //traceback(error);
699 | logger.error(
700 | `[${this.bot_name}] | ${this.session_name} | ❗️Unknown error: ${error}}`
701 | );
702 | } finally {
703 | let ran_sleep;
704 | if (_isArray(settings.SLEEP_BETWEEN_TAP)) {
705 | if (
706 | _.isInteger(settings.SLEEP_BETWEEN_TAP[0]) &&
707 | _.isInteger(settings.SLEEP_BETWEEN_TAP[1])
708 | ) {
709 | ran_sleep = _.random(
710 | settings.SLEEP_BETWEEN_TAP[0],
711 | settings.SLEEP_BETWEEN_TAP[1]
712 | );
713 | } else {
714 | ran_sleep = _.random(450, 800);
715 | }
716 | } else if (_.isInteger(settings.SLEEP_BETWEEN_TAP)) {
717 | const ran_add = _.random(20, 50);
718 | ran_sleep = settings.SLEEP_BETWEEN_TAP + ran_add;
719 | } else {
720 | ran_sleep = _.random(450, 800);
721 | }
722 |
723 | logger.info(
724 | `[${this.bot_name}] | ${this.session_name} | Sleeping for ${ran_sleep} seconds...`
725 | );
726 | await sleep(ran_sleep);
727 | }
728 | }
729 | }
730 | }
731 | module.exports = NonSessionTapper;
732 |
--------------------------------------------------------------------------------
/bot/core/tapper.js:
--------------------------------------------------------------------------------
1 | const logger = require("../utils/logger");
2 | const headers = require("./header");
3 | const { Api } = require("telegram");
4 | const settings = require("../config/config");
5 | const app = require("../config/app");
6 | const user_agents = require("../config/userAgents");
7 | const fs = require("fs");
8 | const sleep = require("../utils/sleep");
9 | const ApiRequest = require("./api");
10 | const parser = require("../utils/parser");
11 | const _ = require("lodash");
12 | const moment = require("moment");
13 | const filterArray = require("../helpers/filterArray");
14 | const upgradeTabCardsBuying = require("../scripts/upgradeTabCardsBuying");
15 | const upgradeNoConditionCards = require("../scripts/upgradeNoConditionCards");
16 | const path = require("path");
17 | const _isArray = require("../utils/_isArray");
18 | const fdy = require("fdy-scraping");
19 | const FdyTmp = require("fdy-tmp");
20 |
21 | class Tapper {
22 | constructor(tg_client) {
23 | this.bot_name = "rockyrabbit";
24 | this.session_name = tg_client.session_name;
25 | this.tg_client = tg_client.tg_client;
26 | this.API_URL = app.apiUrl;
27 | this.session_user_agents = this.#load_session_data();
28 | this.headers = { ...headers, "user-agent": this.#get_user_agent() };
29 | this.api = new ApiRequest(this.session_name, this.bot_name);
30 | this.sleep_floodwait = 0;
31 | this.runOnce = false;
32 | this.bot = null;
33 | }
34 |
35 | #load_session_data() {
36 | try {
37 | const filePath = path.join(process.cwd(), "session_user_agents.json");
38 | const data = fs.readFileSync(filePath, "utf8");
39 | return JSON.parse(data);
40 | } catch (error) {
41 | if (error.code === "ENOENT") {
42 | return {};
43 | } else {
44 | throw error;
45 | }
46 | }
47 | }
48 |
49 | #clean_tg_web_data(queryString) {
50 | let cleanedString = queryString.replace(/^tgWebAppData=/, "");
51 | cleanedString = cleanedString.replace(
52 | /&tgWebAppVersion=.*?&tgWebAppPlatform=.*?(?:&tgWebAppBotInline=.*?)?$/,
53 | ""
54 | );
55 | return cleanedString;
56 | }
57 |
58 | #get_random_user_agent() {
59 | const randomIndex = Math.floor(Math.random() * user_agents.length);
60 | return user_agents[randomIndex];
61 | }
62 |
63 | #get_user_agent() {
64 | if (this.session_user_agents[this.session_name]) {
65 | return this.session_user_agents[this.session_name];
66 | }
67 |
68 | logger.info(
69 | `[${this.bot_name}] | ${this.session_name} | Generating new user agent...`
70 | );
71 | const newUserAgent = this.#get_random_user_agent();
72 | this.session_user_agents[this.session_name] = newUserAgent;
73 | this.#save_session_data(this.session_user_agents);
74 | return newUserAgent;
75 | }
76 |
77 | #save_session_data(session_user_agents) {
78 | const filePath = path.join(process.cwd(), "session_user_agents.json");
79 | fs.writeFileSync(filePath, JSON.stringify(session_user_agents, null, 2));
80 | }
81 |
82 | #get_boost_by_id(data, boostId) {
83 | const boost = data.boostsList.find((boost) => boost.boostId === boostId);
84 | return boost ? boost : {};
85 | }
86 |
87 | #get_platform(userAgent) {
88 | const platformPatterns = [
89 | { pattern: /iPhone/i, platform: "ios" },
90 | { pattern: /Android/i, platform: "android" },
91 | { pattern: /iPad/i, platform: "ios" },
92 | ];
93 |
94 | for (const { pattern, platform } of platformPatterns) {
95 | if (pattern.test(userAgent)) {
96 | return platform;
97 | }
98 | }
99 |
100 | return "Unknown";
101 | }
102 |
103 | async #get_tg_web_data() {
104 | try {
105 | const tmp = new FdyTmp({
106 | fileName: `${this.bot_name}.fdy.tmp`,
107 | tmpPath: path.join(process.cwd(), "cache/queries"),
108 | });
109 | if (tmp.hasJsonElement(this.session_name)) {
110 | const queryStringFromCache = tmp.getJson(this.session_name);
111 | if (!_.isEmpty(queryStringFromCache)) {
112 | this.headers["authorization"] = `tma ${queryStringFromCache}`;
113 | const va_hc = fdy.create({
114 | headers: this.headers,
115 | });
116 |
117 | const validate = await this.api.validate(va_hc);
118 |
119 | if (validate) {
120 | logger.info(
121 | `[${this.bot_name}] | ${this.session_name} | 🔄 Getting data from cache...`
122 | );
123 | if (this.tg_client.connected) {
124 | await this.tg_client.disconnect();
125 | await this.tg_client.destroy();
126 | }
127 | await sleep(5);
128 | return queryStringFromCache;
129 | } else {
130 | tmp.deleteJsonElement(this.session_name);
131 | }
132 | }
133 | }
134 | await this.tg_client.connect();
135 | await this.tg_client.start();
136 | const platform = this.#get_platform(this.#get_user_agent());
137 |
138 | if (!this.bot) {
139 | this.bot = await this.tg_client.getInputEntity(app.bot);
140 | }
141 |
142 | if (!this.runOnce) {
143 | logger.info(
144 | `[${this.bot_name}] | ${this.session_name} | 📡 Waiting for authorization...`
145 | );
146 | const botHistory = await this.tg_client.invoke(
147 | new Api.messages.GetHistory({
148 | peer: this.bot,
149 | limit: 10,
150 | })
151 | );
152 | if (botHistory.messages.length < 1) {
153 | await this.tg_client.invoke(
154 | new Api.messages.SendMessage({
155 | message: "/start",
156 | silent: true,
157 | noWebpage: true,
158 | peer: this.bot,
159 | })
160 | );
161 | }
162 | }
163 |
164 | await sleep(5);
165 |
166 | const result = await this.tg_client.invoke(
167 | new Api.messages.RequestWebView({
168 | peer: this.bot,
169 | bot: this.bot,
170 | platform,
171 | from_bot_menu: true,
172 | url: app.webviewUrl,
173 | })
174 | );
175 |
176 | const authUrl = result.url;
177 | const tgWebData = authUrl.split("#", 2)[1];
178 | logger.info(
179 | `[${this.bot_name}] | ${this.session_name} | 💾 Storing data in cache...`
180 | );
181 |
182 | await sleep(5);
183 |
184 | tmp
185 | .addJson(
186 | this.session_name,
187 | decodeURIComponent(this.#clean_tg_web_data(tgWebData))
188 | )
189 | .save();
190 | return decodeURIComponent(this.#clean_tg_web_data(tgWebData));
191 | } catch (error) {
192 | if (error.message.includes("AUTH_KEY_DUPLICATED")) {
193 | logger.error(
194 | `[${this.bot_name}] | ${this.session_name} | The same authorization key (session file) was used in more than one place simultaneously. You must delete your session file and create a new session`
195 | );
196 | return null;
197 | }
198 | const regex = /A wait of (\d+) seconds/;
199 | if (
200 | error.message.includes("FloodWaitError") ||
201 | error.message.match(regex)
202 | ) {
203 | const match = error.message.match(regex);
204 |
205 | if (match) {
206 | this.sleep_floodwait =
207 | new Date().getTime() / 1000 + parseInt(match[1], 10) + 10;
208 | } else {
209 | this.sleep_floodwait = new Date().getTime() / 1000 + 50;
210 | }
211 | logger.error(
212 | `[${this.bot_name}] | ${
213 | this.session_name
214 | } | Some flood error, waiting ${
215 | this.sleep_floodwait - new Date().getTime() / 1000
216 | } seconds to try again...`
217 | );
218 | } else {
219 | logger.error(
220 | `[${this.bot_name}] | ${this.session_name} | ❗️Unknown error during Authorization: ${error}`
221 | );
222 | }
223 | return null;
224 | } finally {
225 | if (this.tg_client.connected) {
226 | await this.tg_client.disconnect();
227 | await this.tg_client.destroy();
228 | }
229 | this.runOnce = true;
230 | if (this.sleep_floodwait > new Date().getTime() / 1000) {
231 | await sleep(this.sleep_floodwait - new Date().getTime() / 1000);
232 | return await this.#get_tg_web_data();
233 | }
234 | await sleep(3);
235 | }
236 | }
237 |
238 | async #check_proxy(http_client, proxy) {
239 | try {
240 | const response = await http_client.get("https://httpbin.org/ip");
241 | const ip = response.data.origin;
242 | logger.info(
243 | `[${this.bot_name}] | ${this.session_name} | Proxy IP: ${ip}`
244 | );
245 | } catch (error) {
246 | logger.error(
247 | `[${this.bot_name}] | ${this.session_name} | Error: Unable to resolve the proxy address. The proxy server at ${proxy?.ip}:${proxy?.port} could not be found. Please check the proxy address and your network connection.`
248 | );
249 | logger.error(
250 | `[${this.bot_name}] | ${this.session_name} | No proxy will be used.`
251 | );
252 | logger.error(
253 | `[${this.bot_name}] | ${this.session_name} | Error message: ${error?.message}`
254 | );
255 |
256 | return false;
257 | }
258 | }
259 |
260 | async #get_user_data(http_client) {
261 | let profile_data = false;
262 | while (typeof profile_data === "boolean" && !profile_data) {
263 | profile_data = await this.api.get_user_data(http_client);
264 | if (profile_data === false) {
265 | logger.warning(
266 | `[${this.bot_name}] | ${this.session_name} | Unable to get user data. Retrying...`
267 | );
268 | await sleep(5);
269 | continue;
270 | }
271 |
272 | if (_.isNull(profile_data) || _.isEmpty(profile_data)) {
273 | logger.warning(
274 | `[${this.bot_name}] | ${this.session_name} | Error while getting user data. Aborting...`
275 | );
276 | break;
277 | }
278 |
279 | return profile_data;
280 | }
281 | return null;
282 | }
283 |
284 | async run(proxy) {
285 | let http_client;
286 | let access_token_created_time = 0;
287 |
288 | let profile_data, boosts_list;
289 | let sleep_daily_reward = 0;
290 | let tasks_list = {};
291 | let config = {};
292 | let get_daily_sync_info = {};
293 | let mine_sync = [];
294 | let exceeded_energy = 0;
295 | let exceeded_turbo = 0;
296 | let sleep_empty_energy = 0;
297 |
298 | if (settings.USE_PROXY_FROM_FILE && proxy) {
299 | http_client = fdy.create({
300 | headers: this.headers,
301 | proxy,
302 | });
303 | const proxy_result = await this.#check_proxy(http_client, proxy);
304 | if (!proxy_result) {
305 | http_client = fdy.create({
306 | headers: this.headers,
307 | });
308 | }
309 | } else {
310 | http_client = fdy.create({
311 | headers: this.headers,
312 | });
313 | }
314 |
315 | while (true) {
316 | try {
317 | const currentTime = _.floor(Date.now() / 1000);
318 | if (currentTime - access_token_created_time >= 14400) {
319 | http_client.defaults.headers["sec-ch-ua-platform"] =
320 | this.#get_platform(this.#get_user_agent());
321 |
322 | const tg_web_data = await this.#get_tg_web_data();
323 |
324 | if (
325 | _.isNull(tg_web_data) ||
326 | _.isUndefined(tg_web_data) ||
327 | !tg_web_data ||
328 | _.isEmpty(tg_web_data)
329 | ) {
330 | await sleep(5);
331 | continue;
332 | }
333 |
334 | http_client.defaults.headers["authorization"] = `tma ${tg_web_data}`;
335 |
336 | access_token_created_time = currentTime;
337 | await sleep(5);
338 | }
339 | // Get profile data
340 | profile_data = await this.#get_user_data(http_client);
341 | boosts_list = await this.api.get_boosts(http_client);
342 | tasks_list = await this.api.tasks(http_client);
343 | config = await this.api.config(http_client);
344 | mine_sync = await this.api.mine_sync(http_client);
345 | get_daily_sync_info = await this.api.get_daily_sync_info(http_client);
346 |
347 | if (
348 | _.isEmpty(profile_data) ||
349 | profile_data?.status?.toLowerCase() !== "ok"
350 | ) {
351 | access_token_created_time = 0;
352 | await sleep(5);
353 |
354 | continue;
355 | }
356 |
357 | if (!profile_data?.initAccount || _.isEmpty(profile_data?.account)) {
358 | await this.api.init_account(http_client);
359 | await this.api.sponsor(http_client);
360 | continue;
361 | }
362 |
363 | if (profile_data?.account?.sponsor == "") {
364 | await this.api.sponsor(http_client);
365 | continue;
366 | }
367 |
368 | await sleep(2);
369 |
370 | if (profile_data?.clicker?.lastPassiveEarn > 0) {
371 | logger.info(
372 | `[${this.bot_name}] | ${this.session_name} | 💸 Last passive earn: +${profile_data?.clicker?.lastPassiveEarn} | Earn per hour: ${profile_data?.clicker?.earnPassivePerHour}`
373 | );
374 | }
375 |
376 | // Daily reward
377 | if (settings.AUTO_CLAIM_REWARD && sleep_daily_reward <= currentTime) {
378 | const reward_data = await this.api.daily_reward(http_client);
379 |
380 | if (
381 | typeof reward_data === "string" &&
382 | reward_data.includes("not_subscribed")
383 | ) {
384 | logger.info(
385 | `[${this.bot_name}] | ${this.session_name} |⌛Joining RockyRabit channel before claiming daily reward...`
386 | );
387 | await this.tg_client.invoke(
388 | new Api.channels.JoinChannel({
389 | channel: await this.tg_client.getInputEntity(
390 | app.rockyRabitChannel
391 | ),
392 | })
393 | );
394 | continue;
395 | } else if (
396 | typeof reward_data === "string" &&
397 | reward_data.includes("claimed")
398 | ) {
399 | sleep_daily_reward =
400 | new Date(moment().add(1, "days").startOf("day")).getTime() / 1000;
401 | logger.info(
402 | `[${this.bot_name}] | ${this.session_name} | 🚶 Daily reward already claimed. Skipping...`
403 | );
404 | } else if (reward_data?.status?.toLowerCase() === "ok") {
405 | profile_data = await this.#get_user_data(http_client);
406 | logger.info(
407 | `[${this.bot_name}] | ${this.session_name} | 🎉 Claimed daily reward successfully | Reward: ${reward_data?.task?.rewardCoins}
| Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}
`
408 | );
409 | sleep_daily_reward =
410 | new Date(moment().add(1, "days").startOf("day")).getTime() / 1000;
411 | }
412 | }
413 |
414 | await sleep(1);
415 |
416 | //Send taps
417 | if (settings.RANDOM_TAPS_COUNT[0] > settings.RANDOM_TAPS_COUNT[1]) {
418 | logger.error(
419 | `[${this.bot_name}] | ${this.session_name} | ❗️Invalid Random Taps Count. RANDOM_TAPS_COUNT MIN must be less than RANDOM_TAPS_COUNT MAX. Example: RANDOM_TAPS_COUNT: [10, 20]`
420 | );
421 | process.exit(1);
422 | }
423 | if (
424 | !_.isInteger(settings.RANDOM_TAPS_COUNT[0]) ||
425 | !_.isInteger(settings.RANDOM_TAPS_COUNT[1])
426 | ) {
427 | logger.error(
428 | `[${this.bot_name}] | ${this.session_name} | ❗️Invalid Random Taps Count. RANDOM_TAPS_COUNT MIN and MAX must be integers/numbers. Example: RANDOM_TAPS_COUNT: [10, 20]`
429 | );
430 | process.exit(1);
431 | }
432 | let taps_sent_count = 0;
433 | if (sleep_empty_energy <= currentTime) {
434 | while (
435 | profile_data?.clicker?.availableTaps >
436 | settings.MIN_AVAILABLE_ENERGY &&
437 | taps_sent_count < 10
438 | ) {
439 | await sleep(_.random(5, 15));
440 | let taps = _.random(
441 | settings.RANDOM_TAPS_COUNT[0],
442 | settings.RANDOM_TAPS_COUNT[1]
443 | );
444 | boosts_list = await this.api.get_boosts(http_client);
445 | if (
446 | !moment(exceeded_turbo * 1000).isSame(new Date().getTime(), "day")
447 | ) {
448 | const turbo_data = this.#get_boost_by_id(boosts_list, "turbo");
449 |
450 | const turbo_boost = await this.api.upgrade_boost(http_client, {
451 | boostId: turbo_data?.boostId,
452 | timezone: app.timezone,
453 | });
454 |
455 | if (turbo_boost?.status?.toLowerCase() === "ok") {
456 | logger.info(
457 | `[${this.bot_name}] | ${this.session_name} | ⏩ Turbo boost activated.`
458 | );
459 | await sleep(5);
460 | } else if (
461 | typeof turbo_boost == "string" &&
462 | turbo_boost.includes("exceeded")
463 | ) {
464 | exceeded_turbo = currentTime;
465 | }
466 | }
467 |
468 | const taps_can_send =
469 | profile_data?.clicker?.availableTaps /
470 | profile_data?.clicker?.earnPerTap;
471 | const count =
472 | taps > _.floor(taps_can_send) ? _.floor(taps_can_send) : taps;
473 | const taps_result = await this.api.taps(http_client, { count });
474 |
475 | if (taps_result?.status?.toLowerCase() === "ok") {
476 | const balanceChange =
477 | taps_result?.clicker?.balance - profile_data?.clicker?.balance;
478 | profile_data = await this.#get_user_data(http_client);
479 | logger.info(
480 | `[${this.bot_name}] | ${this.session_name} | ✅ Taps sent successfully | Balance: ${profile_data?.clicker?.balance} (+${balanceChange}) | Total: ${profile_data?.clicker?.totalBalance}
| Available energy: ${profile_data?.clicker?.availableTaps}`
481 | );
482 | }
483 |
484 | profile_data = await this.#get_user_data(http_client);
485 | boosts_list = await this.api.get_boosts(http_client);
486 |
487 | if (
488 | profile_data?.clicker?.availableTaps <=
489 | settings.MIN_AVAILABLE_ENERGY
490 | ) {
491 | if (_.isEmpty(boosts_list)) {
492 | break;
493 | }
494 | const full_taps_data = this.#get_boost_by_id(
495 | boosts_list,
496 | "full-available-taps"
497 | );
498 | if (_.isEmpty(full_taps_data)) {
499 | break;
500 | }
501 |
502 | if (
503 | full_taps_data?.lastUpgradeAt + 3605 <= currentTime &&
504 | settings.APPLY_DAILY_FULL_ENERGY &&
505 | !moment(exceeded_energy * 1000).isSame(
506 | new Date().getTime(),
507 | "day"
508 | )
509 | ) {
510 | const full_energy_boost = await this.api.upgrade_boost(
511 | http_client,
512 | {
513 | boostId: full_taps_data?.boostId,
514 | timezone: app.timezone,
515 | }
516 | );
517 |
518 | if (
519 | typeof full_energy_boost == "string" &&
520 | full_energy_boost.includes("exceeded")
521 | ) {
522 | exceeded_energy = currentTime;
523 | break;
524 | }
525 |
526 | if (full_energy_boost?.status?.toLowerCase() === "ok") {
527 | profile_data = await this.#get_user_data(http_client);
528 | logger.info(
529 | `[${this.bot_name}] | ${this.session_name} | 🔋Full energy boost applied successfully`
530 | );
531 | }
532 | } else {
533 | profile_data = await this.#get_user_data(http_client);
534 | sleep_empty_energy = currentTime + settings.SLEEP_EMPTY_ENERGY;
535 |
536 | logger.info(
537 | `[${this.bot_name}] | ${
538 | this.session_name
539 | } | Not enough energy to send ${count} taps. Needed ${
540 | count * profile_data?.clicker?.earnPerTap
541 | } energy to send taps | Available: ${
542 | profile_data?.clicker?.availableTaps
543 | } | Sleeping ${settings.SLEEP_EMPTY_ENERGY}s`
544 | );
545 | break;
546 | }
547 | }
548 |
549 | taps_sent_count++;
550 | }
551 | }
552 |
553 | await sleep(2);
554 |
555 | // Daily combos
556 | const combo_data = await this.api.get_combo_data(http_client);
557 | if (!_.isEmpty(combo_data)) {
558 | const expireAtForCards =
559 | new Date(combo_data?.expireAtForCards).getTime() / 1000;
560 |
561 | const expireAtForEaster =
562 | new Date(combo_data?.expireAtForEaster).getTime() / 1000;
563 |
564 | if (
565 | settings.AUTO_PLAY_ENIGMA &&
566 | !_.isEmpty(combo_data?.enigma) &&
567 | !_.isEmpty(get_daily_sync_info)
568 | ) {
569 | const play_enigma_data = get_daily_sync_info?.enigma;
570 |
571 | if (
572 | play_enigma_data?.completedAt < 1 &&
573 | Array.isArray(combo_data?.enigma) &&
574 | play_enigma_data?.passphrase?.includes(combo_data?.enigma[0])
575 | ) {
576 | const play_enigma = await this.api.play_enigma(http_client, {
577 | passphrase: Array.isArray(combo_data?.enigma)
578 | ? combo_data.enigma.join(",")
579 | : combo_data.enigma,
580 | enigmaId: play_enigma_data?.enigmaId,
581 | });
582 |
583 | if (play_enigma?.status?.toLowerCase() === "ok") {
584 | profile_data = await this.#get_user_data(http_client);
585 | logger.info(
586 | `[${this.bot_name}] | ${this.session_name} | 🎊 Enigma claimed successfully | Reward: ${play_enigma_data?.amount} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}
`
587 | );
588 | }
589 | }
590 | }
591 |
592 | if (
593 | settings.AUTO_PLAY_COMBO &&
594 | !_.isEmpty(combo_data?.cards) &&
595 | !_.isEmpty(get_daily_sync_info)
596 | ) {
597 | const combo_info = get_daily_sync_info?.superSet;
598 |
599 | if (combo_info?.completedAt < 1 && expireAtForCards > currentTime) {
600 | const play_combo = await this.api.play_combo(http_client, {
601 | combos: Array.isArray(combo_data?.cards)
602 | ? combo_data?.cards.join(",")
603 | : combo_data?.cards,
604 | comboId: combo_info?.comboId,
605 | });
606 |
607 | if (play_combo?.status?.toLowerCase() === "ok") {
608 | profile_data = await this.#get_user_data(http_client);
609 | logger.info(
610 | `[${this.bot_name}] | ${this.session_name} | 🎊 Daily combo claimed successfully | Reward: ${play_combo?.winner?.rabbitWinner} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}
`
611 | );
612 | }
613 | }
614 | }
615 |
616 | if (
617 | settings.AUTO_CLAIM_EASTER_EGG &&
618 | !_.isEmpty(combo_data?.easter) &&
619 | !_.isEmpty(get_daily_sync_info?.easterEggs)
620 | ) {
621 | const easter_info = get_daily_sync_info?.easterEggs;
622 |
623 | if (
624 | easter_info?.completedAt < 1 &&
625 | expireAtForEaster > currentTime
626 | ) {
627 | const play_easter = await this.api.play_easter(http_client, {
628 | easter: combo_data?.easter,
629 | easterEggsId: easter_info?.easterEggsId,
630 | });
631 |
632 | if (play_easter?.status?.toLowerCase() === "ok") {
633 | profile_data = await this.#get_user_data(http_client);
634 | logger.info(
635 | `[${this.bot_name}] | ${this.session_name} | 🎊 Easter Egg claimed successfully | Reward: ${easter_info?.amount} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}
`
636 | );
637 | }
638 | }
639 | }
640 | }
641 |
642 | await sleep(3);
643 |
644 | // Boost upgrade (earn-per-tap)
645 | const tap_boost_data = this.#get_boost_by_id(
646 | boosts_list,
647 | "earn-per-tap"
648 | );
649 | if (
650 | settings.AUTO_UPGRADE_TAP &&
651 | !_.isEmpty(tap_boost_data) &&
652 | settings.MAX_TAP_LEVEL > tap_boost_data?.level &&
653 | tap_boost_data?.price <= profile_data?.clicker?.balance
654 | ) {
655 | const tap_boost = await this.api.upgrade_boost(http_client, {
656 | boostId: tap_boost_data?.boostId,
657 | timezone: app.timezone,
658 | });
659 |
660 | if (tap_boost?.status?.toLowerCase() === "ok") {
661 | profile_data = await this.#get_user_data(http_client);
662 | logger.info(
663 | `[${this.bot_name}] | ${this.session_name} | ⬆️ Tap upgraded successfully | Level: ${tap_boost_data?.level} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}
| Available energy: ${profile_data?.clicker?.availableTaps}`
664 | );
665 | }
666 | }
667 | await sleep(3);
668 |
669 | // Boost upgrade (max-taps)
670 | const energy_boost_data = this.#get_boost_by_id(
671 | boosts_list,
672 | "max-taps"
673 | );
674 |
675 | if (
676 | settings.AUTO_UPGRADE_ENERGY_LIMIT &&
677 | !_.isEmpty(energy_boost_data) &&
678 | settings.MAX_ENERGY_LIMIT_LEVEL > energy_boost_data?.level &&
679 | energy_boost_data?.price <= profile_data?.clicker?.balance
680 | ) {
681 | const energy_boost = await this.api.upgrade_boost(http_client, {
682 | boostId: energy_boost_data?.boostId,
683 | timezone: app.timezone,
684 | });
685 | if (energy_boost?.status?.toLowerCase() === "ok") {
686 | profile_data = await this.#get_user_data(http_client);
687 | logger.info(
688 | `[${this.bot_name}] | ${this.session_name} | ⬆️ Energy limit upgraded successfully | Level: ${energy_boost_data?.level} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}
| Available energy: ${profile_data?.clicker?.availableTaps}`
689 | );
690 | }
691 | }
692 |
693 | await sleep(3);
694 |
695 | // Boost upgrade (hourly-income-limit)
696 | const hourly_limit_data = this.#get_boost_by_id(
697 | boosts_list,
698 | "hourly-income-limit"
699 | );
700 |
701 | if (
702 | settings.AUTO_HOURLY_LIMIT &&
703 | !_.isEmpty(hourly_limit_data) &&
704 | settings.MAX_HOURLY_LIMIT_LEVEL > hourly_limit_data?.level &&
705 | hourly_limit_data?.price <= profile_data?.clicker?.balance
706 | ) {
707 | const hourly_limit = await this.api.upgrade_boost(http_client, {
708 | boostId: hourly_limit_data?.boostId,
709 | timezone: app.timezone,
710 | });
711 | if (hourly_limit?.status?.toLowerCase() === "ok") {
712 | profile_data = await this.#get_user_data(http_client);
713 | logger.info(
714 | `[${this.bot_name}] | ${this.session_name} | ⬆️ Hourly limit upgraded successfully | Level: ${hourly_limit_data?.level} | Balance: ${profile_data?.clicker?.balance} | Total: ${profile_data?.clicker?.totalBalance}
| Available energy: ${profile_data?.clicker?.availableTaps}`
715 | );
716 | }
717 | }
718 |
719 | if (settings.AUTO_COMPLETE_TASKS) {
720 | await sleep(2);
721 |
722 | if (!_.isEmpty(tasks_list) && !_.isEmpty(tasks_list.tasks)) {
723 | const uncompletedTasks = filterArray.getUncompletedTasks(
724 | tasks_list.tasks
725 | );
726 |
727 | if (!_.isEmpty(uncompletedTasks)) {
728 | for (const task of uncompletedTasks) {
729 | const complete_task = await this.api.claim_task(http_client, {
730 | taskId: task?.id,
731 | timezone: app.timezone,
732 | });
733 | if (complete_task?.status?.toLowerCase() === "ok") {
734 | logger.info(
735 | `[${this.bot_name}] | ${this.session_name} | ✔️ Task completed successfully | Task title: ${task?.name} | Reward: ${task?.rewardCoins}
`
736 | );
737 | } else {
738 | logger.error(
739 | `[${this.bot_name}] | ${this.session_name} | ✖️ Could not complete task | Task title: ${task?.name} | Reward: ${task?.rewardCoins}
`
740 | );
741 | }
742 | }
743 | }
744 | }
745 | }
746 |
747 | if (settings.AUTO_UPGRADE_CARD) {
748 | if (
749 | _.isEmpty(config?.config) ||
750 | _.isEmpty(config?.config?.upgrade) ||
751 | _.isEmpty(mine_sync)
752 | ) {
753 | continue;
754 | }
755 |
756 | const leagues = Array.from(
757 | { length: 10 },
758 | (_, i) => filterArray.getById(mine_sync, `league_${i + 1}`)[0]
759 | );
760 |
761 | if (leagues.some((league) => _.isEmpty(league))) {
762 | continue;
763 | }
764 |
765 | const cards_fighter = filterArray.getCardsOnUpgradeTab(
766 | config?.config?.upgrade,
767 | "fighter",
768 | "upgrade"
769 | );
770 | const cards_coach = filterArray.getCardsOnUpgradeTab(
771 | config?.config?.upgrade,
772 | "coach",
773 | "upgrade"
774 | );
775 |
776 | if (_.isEmpty(cards_fighter) || _.isEmpty(cards_coach)) {
777 | continue;
778 | }
779 |
780 | for (let i = 0; i < leagues.length; i++) {
781 | const allPreviousLeaguesCompleted =
782 | i === 0 ||
783 | leagues
784 | .slice(0, i)
785 | .every((league) => league?.isCompleted === true);
786 |
787 | if (
788 | leagues[i]?.isCompleted === false &&
789 | allPreviousLeaguesCompleted
790 | ) {
791 | const level = i + 1;
792 | const cards_fighter_level = filterArray.getCardsWithLevel(
793 | mine_sync,
794 | cards_fighter,
795 | level
796 | );
797 | const cards_coach_level = filterArray.getCardsWithLevel(
798 | mine_sync,
799 | cards_coach,
800 | level
801 | );
802 |
803 | if (!_.isEmpty(cards_fighter_level)) {
804 | await upgradeTabCardsBuying(
805 | cards_fighter_level,
806 | http_client,
807 | this.api,
808 | this.session_name,
809 | this.bot_name
810 | );
811 | mine_sync = await this.api.mine_sync(http_client);
812 | continue;
813 | } else if (!_.isEmpty(cards_coach_level)) {
814 | await upgradeTabCardsBuying(
815 | cards_coach_level,
816 | http_client,
817 | this.api,
818 | this.session_name,
819 | this.bot_name
820 | );
821 | mine_sync = await this.api.mine_sync(http_client);
822 | continue;
823 | }
824 |
825 | if (leagues[i]?.price <= profile_data?.clicker?.balance) {
826 | const upgrade_league = await this.api.upgrade_cards(
827 | http_client,
828 | {
829 | upgradeId: `league_${level}`,
830 | }
831 | );
832 |
833 | if (upgrade_league?.status?.toLowerCase() === "ok") {
834 | profile_data = await this.#get_user_data(http_client);
835 |
836 | logger.info(
837 | `[${this.bot_name}] | ${this.session_name} | ⬆️ League_${level} upgraded successfully | Level: ${leagues[i]?.level} | Cost: ${leagues[i]?.price} | Balance: ${profile_data?.clicker?.balance}`
838 | );
839 | }
840 | } else {
841 | logger.info(
842 | `[${this.bot_name}] | ${this.session_name} | 👎 Not enough balance to upgrade league ${level} | Need: ${leagues[i]?.price} | Balance: ${profile_data?.clicker?.balance}
`
843 | );
844 | continue;
845 | }
846 | }
847 | }
848 |
849 | await sleep(2);
850 |
851 | // get cards with no conditions
852 | const cards_wnc = filterArray.getEmptyConditions(
853 | config?.config?.upgrade
854 | );
855 |
856 | await upgradeNoConditionCards(
857 | cards_wnc,
858 | this.api,
859 | http_client,
860 | this.session_name,
861 | this.bot_name
862 | );
863 | }
864 | } catch (error) {
865 | // traceback(error);
866 | logger.error(
867 | `[${this.bot_name}] | ${this.session_name} | ❗️Unknown error: ${error}}`
868 | );
869 | } finally {
870 | let ran_sleep;
871 | if (_isArray(settings.SLEEP_BETWEEN_TAP)) {
872 | if (
873 | _.isInteger(settings.SLEEP_BETWEEN_TAP[0]) &&
874 | _.isInteger(settings.SLEEP_BETWEEN_TAP[1])
875 | ) {
876 | ran_sleep = _.random(
877 | settings.SLEEP_BETWEEN_TAP[0],
878 | settings.SLEEP_BETWEEN_TAP[1]
879 | );
880 | } else {
881 | ran_sleep = _.random(450, 800);
882 | }
883 | } else if (_.isInteger(settings.SLEEP_BETWEEN_TAP)) {
884 | const ran_add = _.random(20, 50);
885 | ran_sleep = settings.SLEEP_BETWEEN_TAP + ran_add;
886 | } else {
887 | ran_sleep = _.random(450, 800);
888 | }
889 |
890 | logger.info(
891 | `[${this.bot_name}] | ${this.session_name} | Sleeping for ${ran_sleep} seconds...`
892 | );
893 | await sleep(ran_sleep);
894 | }
895 | }
896 | }
897 | }
898 | module.exports = Tapper;
899 |
--------------------------------------------------------------------------------