├── .github └── workflows │ └── main.yml ├── .gitignore ├── README.md ├── accounts.py ├── bots ├── altooshka │ ├── __init__.py │ ├── client.py │ └── strings.py ├── anon │ ├── __init__.py │ ├── client.py │ └── strings.py ├── base │ ├── DEV_GUIDE.md │ ├── __init__.py │ ├── base.py │ ├── strings.py │ └── utils.py ├── blum │ ├── __init__.py │ ├── client.py │ ├── config.py │ └── strings.py ├── cell │ ├── __init__.py │ ├── client.py │ ├── strings.py │ └── utils.py ├── dogs │ ├── __init__.py │ ├── client.py │ ├── config.py │ └── strings.py ├── hamster_kombat │ ├── __init__.py │ ├── client.py │ ├── config.py │ ├── promo.py │ ├── strings.py │ └── utils.py ├── hexn │ ├── __init__.py │ ├── client.py │ └── strings.py ├── iceberg │ ├── __init__.py │ ├── client.py │ └── strings.py ├── onewin │ ├── __init__.py │ ├── client.py │ ├── config.py │ └── strings.py ├── orbitonx │ ├── __init__.py │ ├── client.py │ └── strings.py ├── race │ ├── __init__.py │ ├── client.py │ └── strings.py ├── simple │ ├── __init__.py │ ├── client.py │ ├── config.py │ ├── strings.py │ └── utils.py ├── solstone │ ├── client.py │ ├── strings.py │ └── utils.py ├── tapcoins │ ├── __init__.py │ ├── client.py │ ├── config.py │ └── strings.py ├── template │ ├── __init__.py │ ├── client.py │ └── strings.py ├── timeton │ ├── __init__.py │ ├── client.py │ └── strings.py └── zavod │ ├── __init__.py │ ├── client.py │ └── strings.py ├── config.py ├── factory.py ├── initiator.py ├── requirements.txt └── utils.py /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Inline Message Workflow 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | 7 | jobs: 8 | send-inline-message: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v4 13 | 14 | - name: Send Inline Telegram Message 15 | uses: cbrgm/telegram-github-action@v1 16 | with: 17 | token: ${{ secrets.TELEGRAM_TOKEN }} 18 | to: ${{ secrets.TELEGRAM_CHAT_ID }} 19 | message: | 20 | New commit 21 | # New commit by ${{ github.actor }}! 22 | # Commit: ${{ github.event.head_commit.message }} 23 | # Repository: ${{ github.repository }} 24 | # View changes: https://github.com/${{ github.repository }}/commit/${{ github.sha }} 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | .env 3 | venv 4 | *local.py 5 | *.session* 6 | .json 7 | *.json 8 | *.log 9 | .idea 10 | .sandbox.py 11 | .github 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Проект закрыт и ушел в архив. 2 | 3 | # BotFarmFactory 4 | Небольшой "фрейемворк" для создания ферм по прокачке телеграм "тапалок" 5 | 6 | ## Использование 7 | Примерынй алгоритм действий: 8 | 1. В `config.py` находится конфигурация клиента Telegram, ее желательно не трогать. Так же есть флаг DEBUG. (при значении True будет писать диагностическую информацию в файл debug.log) 9 | 1. Отредактировать `config.py`: 10 | 11 | | Параметр | Описание | 12 | | - | - | 13 | | `ACCOUNTS_DIR` | Дефолтное имя каталога, где будут храниться сессии телеграм. | 14 | | `TELEGRAM_AUTH` | Не трогать, если не понимаете что делаете. Это кредсы для работы бота с телеграм аккаунтами. | 15 | | `DEBUG` | Включение записи диагностической информации в `debug.log` | 16 | | `RETRY_ATTEMPTS` | Количество ретраев при запросах | 17 | | `ENABLED_BOTS` | Список включенных ботов. Пустой список - все боты |включены. Если добавить хоть один бот - работать будет только он. | 18 | | `DISABLED_BOTS` | Список выключенных ботов. Все боты что в списке будут выключены. | 19 | | `SLEEP_AT_NIGHT` | Атрибут указывает, стоит ли боту фармить ночью | 20 | | `NIGHT_HOURS` | Ночные часы (с какого часа и по какой) бот "спит" | 21 | | `MULTITHREAD` | Многопоточность. В боте реализована небольшая многопоточность. При включении боты для каждого аккаунта телеграм будут фармиться в отдельных потоках. То есть аккаунты будут фармиться не один за другим, а параллельно. | 22 | 23 | **ВАЖНО: Многопоточность стоит включать после того, как будут созданы сессии для аккаунтов** 24 | 25 | 2. Заполнить файл `accounts.py` (`accounts_local.py`) здесь нужен номер телефона на котором висит телеграм аккаунт и прокси, через который будут ходить все тапалки на этом аккаунте. 26 | 3. Устновить python 3 (если вдруг не установлен, инструкции есть в интернете) 27 | 4. Установить зависимости выполнив команду в терминале `pip install -r requirements.txt` (если перекачали скрипт, стоит каждый раз это выполнять. может измениться набор пакетов) 28 | 5. Запустить фарминг `python3 factory.py` 29 | 30 | После запуска, бот аутентифицируется в учетках телеграма и под каждой учеткой получает токены и прочие кредсы для доступа к ботам, с которыми бот умеет работать. 31 | 32 | 33 | ## Для разработчиков 34 | Т.к. тащить фабрику и огромное количество ботов в одного - уже непостяжимая задача, было бы неплохо если бы разработчики брались за написание модулей для фабрики и помогали [комьюнити](https://t.me/cryptoautofarm) расти. 35 | Я постараюсь описать методы, атрибуты и подходы которые помогут в написании модулей. [Руководство будет здесь](bots/base/DEV_GUIDE.md) 36 | 37 | В данный момент реализованы боты: 38 | 39 | - [cellcoin_bot](https://t.me/cellcoin_bot?start=102796269) 40 | - [simple_tap_bot](https://t.me/Simple_Tap_Bot?start=1718085881160) 41 | - [blum](https://t.me/BlumCryptoBot/app?startapp=ref_ItXoLRFElL) 42 | - [iceberg](https://t.me/IcebergAppBot?start=referral_102796269) 43 | - [MDAO Wallet (ZAVOD)](https://t.me/Mdaowalletbot?start=102796269) 44 | - [anon](https://t.me/AnonEarnBot) (Если не регается, ищем рефки в интернете) 45 | - [hamster kombat](https://t.me/Hamster_kombat_bot/start?startapp=kentId102796269) 46 | - [timeton](https://t.me/TimeTONbot?start=TotalAwesome) 47 | - [Solstone](https://t.me/solstonebot?start=102796269) 48 | - [Race meme](https://t.me/Racememe_bot?start=_102796269) 49 | 50 | ### Комьюнити модули: 51 | 52 | - [TapCoinsBot](https://t.me/tapcoinsbot/app?startapp=ref_QjG2zG) 53 | - [HEXN](https://t.me/hexn_bot/app?startapp=63b093b0-fcb8-41b5-8f50-bc61983ef4e3) 54 | - [AltOOshka](https://t.me/altooshka_bot?start=z6HfRqEhax4) 55 | - [DOGS](https://t.me/dogshouse_bot/join?startapp=07wokQJZTrS5FSrah8SigQ) 56 | 57 | Боты начнут последовательно (или параллельно) фармить на каждом аккаунте 58 | 59 | Если все выполнено правильно, вы увидите примерно следующую картину: 60 | ![image](https://github.com/TotalAwesome/BotFarmFactory/assets/39047158/a0e77b95-5ae1-4f64-b68d-cb904c0866b7) 61 | 62 | Ответы почти на все вопросы уже есть в канале или в чате и в закрепе: https://t.me/cryptoearnfactory 63 | 64 | ### Донаты приветствуются: 65 | 66 | USDT TRC20: `TQDFebuhjHNZscWKQW79mUCGK3EwihWn8g` 67 | 68 | USDT TON: `UQA4gLdTxkyGNahS3CEpbkbbb8Ktd5S27yOBby2KAF1zKwWC` 69 | 70 | TON: `UQA4gLdTxkyGNahS3CEpbkbbb8Ktd5S27yOBby2KAF1zKwWC` 71 | -------------------------------------------------------------------------------- /accounts.py: -------------------------------------------------------------------------------- 1 | TELEGRAM_ACCOUNTS = [ 2 | dict(phone='+99999999999', proxy="http://user:pass@host:port"), 3 | dict(phone='+99999999991', proxy="https://user:pass@host:port"), 4 | dict(phone='+55555555544'), 5 | ] 6 | 7 | try: 8 | from accounts_local import * 9 | except ImportError: 10 | pass 11 | -------------------------------------------------------------------------------- /bots/altooshka/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /bots/altooshka/client.py: -------------------------------------------------------------------------------- 1 | """ 2 | Author: Eyn 3 | Date: 22-07-2024 4 | 5 | """ 6 | from time import sleep, time 7 | 8 | from bots.altooshka.strings import HEADERS, URL_INIT, URL_LOGIN, URL_GIRLS_ACTION, MSG_ACTION_COMPLETE, \ 9 | MSG_ACTION_IS_NOT_AVAILABLE, MSG_ACTION_UNDRESS_COMPLETE, URL_FOLLOW, URL_X_CHALLENGE, MSG_CURRENT_BALANCE, \ 10 | URL_TG_CHAT, URL_TG_GROUP 11 | from bots.base.base import BaseFarmer 12 | 13 | DEFAULT_EST_TIME = 60 * 10 14 | SLEEP_DURATION = 5 15 | ACTION_COUNT = 7 16 | EARLY_ACTIONS = 3 17 | FOLLOW_ACTION_INDEX = 6 18 | 19 | 20 | class BotFarmer(BaseFarmer): 21 | name = "altooshka_bot" 22 | balance = None 23 | girls = None 24 | auth_data = None 25 | end_time = None 26 | extra_code = 'z6HfRqEhax4' 27 | initialization_data = dict(peer=name, bot=name, url=URL_INIT, start_param=extra_code) 28 | 29 | def set_headers(self, *args, **kwargs): 30 | self.headers = HEADERS.copy() 31 | 32 | def authenticate(self, *args, **kwargs): 33 | init_data = self.initiator.get_auth_data(**self.initialization_data) 34 | self.auth_data = init_data['authData'] 35 | login_url = URL_LOGIN + '?' + self.auth_data + '&ref_code=' + self.extra_code 36 | 37 | result = self.get(login_url, return_codes=(404,)) 38 | 39 | if result.status_code == 201: 40 | self.handle_successful_login(result.json()) 41 | else: 42 | self.handle_failed_login(login_url) 43 | 44 | def handle_successful_login(self, json_data): 45 | if json_data['status'] == 'success' and json_data['success']: 46 | user_data = json_data['data']['user'] 47 | self.balance = user_data['gems'] 48 | self.girls = user_data['girls'] 49 | self.is_alive = True 50 | 51 | def handle_failed_login(self, login_url): 52 | self.initiator.join_group(URL_TG_CHAT) 53 | self.initiator.subscribe_channel(URL_TG_GROUP) 54 | result = self.get(URL_FOLLOW + '?' + self.auth_data) 55 | json = result.json() 56 | if json['success'] and json['data']['isFollowed']: 57 | result = self.post(login_url, return_codes=(404,)) 58 | json = result.json() 59 | if json['success']: 60 | self.handle_successful_login(json) 61 | self.log(MSG_CURRENT_BALANCE.format(balance=self.balance)) 62 | self.do_x_challenge() 63 | self.is_alive = True 64 | 65 | def set_start_time(self): 66 | self.start_time = self.end_time if self.end_time else time() + DEFAULT_EST_TIME 67 | 68 | def set_end_time(self, action_end_time): 69 | if self.end_time is None or action_end_time < self.end_time: 70 | self.end_time = action_end_time 71 | 72 | def process_girls(self): 73 | self.update_girls_actions(self.girls) 74 | for girl_id, girl_data in self.girls.items(): 75 | actions = girl_data.get('actions', {}) 76 | action_ids = list(actions.keys()) 77 | 78 | self.process_first_actions(girl_id, actions, action_ids) 79 | self.process_follow_action(girl_id, actions, action_ids) 80 | self.process_remaining_actions(girl_id, actions, action_ids) 81 | 82 | def process_first_actions(self, girl_id, actions, action_ids): 83 | if len(action_ids) < ACTION_COUNT or actions[action_ids[FOLLOW_ACTION_INDEX]] == 0: 84 | for action_id in action_ids[:EARLY_ACTIONS]: 85 | self.try_process_action(girl_id, action_id, actions[action_id]) 86 | 87 | def process_follow_action(self, girl_id, actions, action_ids): 88 | if len(action_ids) >= ACTION_COUNT and actions[action_ids[FOLLOW_ACTION_INDEX]] == 0: 89 | self.try_process_action(girl_id, action_ids[FOLLOW_ACTION_INDEX], actions[action_ids[FOLLOW_ACTION_INDEX]]) 90 | 91 | def process_remaining_actions(self, girl_id, actions, action_ids): 92 | for action_id in action_ids[EARLY_ACTIONS:FOLLOW_ACTION_INDEX]: 93 | self.try_process_action(girl_id, action_id, actions[action_id]) 94 | 95 | def try_process_action(self, girl_id, action_id, action_end_time): 96 | if action_end_time < time(): 97 | self.process_action(girl_id, action_id, action_end_time) 98 | 99 | def process_action(self, girl_id, action_id, action_end_time): 100 | if action_end_time > time(): 101 | self.set_end_time(action_end_time) 102 | return 103 | 104 | sleep(SLEEP_DURATION) 105 | payload = {"girl_id": girl_id, "action_id": action_id} 106 | url = URL_GIRLS_ACTION + '?' + self.auth_data 107 | 108 | response = self.post(url, json=payload, return_codes=(403,)) 109 | response_json = response.json() 110 | 111 | if response_json['success']: 112 | self.handle_successful_action(response_json, girl_id, action_id) 113 | else: 114 | self.log(MSG_ACTION_IS_NOT_AVAILABLE.format(action=action_id, girl=girl_id)) 115 | 116 | def handle_successful_action(self, response_json, girl_id, action_id): 117 | self.balance = response_json['data']['gems'] 118 | self.set_end_time(response_json['data']['availableAt']) 119 | 120 | reward = response_json['data']['gemsChange'] 121 | if reward > 0: 122 | self.log(MSG_ACTION_COMPLETE.format(action=action_id, girl=girl_id, reward=reward)) 123 | else: 124 | self.log(MSG_ACTION_UNDRESS_COMPLETE.format(girl=girl_id, reward=reward)) 125 | 126 | def farm(self): 127 | self.show_balance() 128 | self.process_girls() 129 | 130 | def update_girls_actions(self, data): 131 | min_timestamp = float('inf') 132 | 133 | for key, girl in data.items(): 134 | existing_actions = girl.get("actions", {}) 135 | start_index = (int(key) - 1) * ACTION_COUNT + 1 136 | 137 | for i in range(ACTION_COUNT): 138 | action_id = str(start_index + i) 139 | if action_id not in existing_actions: 140 | existing_actions[action_id] = 0 141 | 142 | girl["actions"] = dict(sorted(existing_actions.items(), key=lambda item: int(item[0]))) 143 | 144 | for action_id, timestamp in existing_actions.items(): 145 | if time() < timestamp < min_timestamp: 146 | min_timestamp = timestamp 147 | 148 | self.end_time = min_timestamp if min_timestamp != float('inf') else None 149 | self.girls = data 150 | 151 | def do_x_challenge(self): 152 | payload = {"actionName": "x_com_channel_subscribe"} 153 | url = URL_X_CHALLENGE + '?' + self.auth_data 154 | self.post(url, json=payload, return_codes=(403, 404)) 155 | 156 | def show_balance(self): 157 | self.log(MSG_CURRENT_BALANCE.format(balance=self.balance)) 158 | -------------------------------------------------------------------------------- /bots/altooshka/strings.py: -------------------------------------------------------------------------------- 1 | URL_INIT = 'https://app.altooshka.io/' 2 | URL_LOGIN = 'https://api.altooshka.io/user/' 3 | URL_FOLLOW = 'https://api.altooshka.io/user/follow/' 4 | URL_GIRLS_ACTION = 'https://api.altooshka.io/girls/action/' 5 | URL_X_CHALLENGE = 'https://api.altooshka.io/action/challenge' 6 | 7 | URL_TG_CHAT = 'https://t.me/AltOOshka_EN' 8 | URL_TG_GROUP = 'https://t.me/altooshka_ton' 9 | 10 | HEADERS = { 11 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 12 | 'Accept-Encoding': 'gzip, deflate, br, zstd', 13 | 'Accept-Language': 'en-US,en;q=0.9', 14 | 'Dnt': '1', 15 | 'Referer': 'https://app.altooshka.io/', 16 | 'Sec-Fetch-Dest': 'iframe', 17 | 'Sec-Fetch-Mode': 'navigate', 18 | 'Sec-Fetch-Site': 'cross-site', 19 | 'Sec-Fetch-User': '?1', 20 | 'Sec-Gpc': '1', 21 | 'Upgrade-Insecure-Requests': '1', 22 | 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1', 23 | } 24 | 25 | MSG_CURRENT_BALANCE = "Текущий баланс: {balance}" 26 | MSG_ACTION_COMPLETE = "Действие {action}, девушка {girl}. +{reward} монет" 27 | MSG_ACTION_UNDRESS_COMPLETE = "Раздел девушку {girl}. {reward} монет" 28 | MSG_ACTION_IS_NOT_AVAILABLE = "Действие {action} для девушки {girl} ещё выполняется" 29 | 30 | MSG_GIRL_ACTIONS_AVAILABLE = "Для девушки {girl} с уровнем {level} открыто {total} действия" 31 | MSG_GIRL_ACTIONS_UNAVAILABLE = "Для девушки {girl} с уровнем {level} нет доступных действий" 32 | MSG_X_CHALLENGE_SUBSCRIBED = "Подписался на канал в X" 33 | -------------------------------------------------------------------------------- /bots/anon/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TotalAwesome/BotFarmFactory/a014a70f66abbe1a46c9796847cd8813764978d1/bots/anon/__init__.py -------------------------------------------------------------------------------- /bots/anon/client.py: -------------------------------------------------------------------------------- 1 | from telethon.types import InputBotAppShortName 2 | from bots.base.utils import to_localtz_timestamp, api_response 3 | from bots.base.base import BaseFarmer, time 4 | from bots.anon.strings import HEADERS, URL_VERIFY, URL_VERIFICATION, URL_CLAIMED, URL_CLAIM, \ 5 | URL_INIT, MSG_CLAIM, MSG_STATE 6 | 7 | 8 | class BotFarmer(BaseFarmer): 9 | 10 | name = 'anonearnbot' 11 | info = {} 12 | app_extra = 'iDb64mAALgfaXGj8gTCDZ1' 13 | payload_base = {} 14 | codes_to_refresh = (403,) 15 | refreshable_token = True 16 | 17 | @property 18 | def initialization_data(self): 19 | return dict(peer=self.name, 20 | app=InputBotAppShortName(self.initiator.get_input_entity(self.name), "app"), 21 | start_param=self.app_extra) 22 | 23 | def set_headers(self, *args, **kwargs): 24 | self.headers = HEADERS.copy() 25 | self.get = api_response(super().get) 26 | self.post = api_response(super().post) 27 | self.delete = api_response(super().delete) 28 | 29 | def refresh_token(self, *args, **kwargs): 30 | self.initiator.connect() 31 | self.authenticate() 32 | self.initiator.disconnect() 33 | 34 | def authenticate(self, *args, **kwargs): 35 | auth_data = self.initiator.get_auth_data(**self.initialization_data)['authData'] 36 | payload = {"hash": auth_data} 37 | self.headers['Anon-Auth'] = auth_data 38 | if self.post(URL_VERIFY, json=payload): 39 | if response := self.post(URL_VERIFICATION, json=payload): 40 | if token := response["data"]["accessToken"]: 41 | self.headers['Authorization'] = f'Bearer {token}' 42 | else: 43 | self.error(f"{self.name} не зарегистрирован по рефке") 44 | self.is_alive = False 45 | 46 | def set_start_time(self): 47 | self.start_time = time() + self.info.get('claimSecondsAvailable', 300) 48 | 49 | @property 50 | def claim_date(self): 51 | return to_localtz_timestamp(self.info['claimDate']) 52 | 53 | def claim(self): 54 | if claimed := self.get(URL_CLAIMED): 55 | self.info = claimed.get('data', {}) 56 | if self.info.get('isButtonEnabled'): 57 | if response := self.post(URL_CLAIM): 58 | self.info = response.get('data', {}) 59 | self.log(MSG_CLAIM) 60 | 61 | def farm(self): 62 | self.claim() 63 | self.log(MSG_STATE.format(balance=self.info.get('personalXPBalance'))) 64 | -------------------------------------------------------------------------------- /bots/anon/strings.py: -------------------------------------------------------------------------------- 1 | URL_INIT = "https://space.anon.tg/" 2 | URL_VERIFY = "https://space-backend.anon.tg/api/auth/verify" # POST {"hash": "initData"} 3 | URL_VERIFICATION = "https://space-backend.anon.tg/api/auth/verification" # POST {"hash": "initData"} 4 | URL_CLAIMED = "https://space-backend.anon.tg/api/user-claim-history/claimed" 5 | URL_CLAIM = "https://space-backend.anon.tg/api/user-claim-history/create" 6 | URL_TASKS = "https://space-backend.anon.tg/api/tasks/all" # GET 7 | URL_BEGIN_TASK = "https://space-backend.anon.tg/api/tasks-history/create" # POST {"uuid": ""} 8 | URL_CLAIM_TASK = "https://space-backend.anon.tg/api/tasks-history/claimed" # POST {"uuid": ""} 9 | URL_CLAIM_DAILY_REWARD = "" 10 | URL_START_GAME = "" 11 | 12 | MSG_CLAIM = "Собрал нафармленное и начал фармить" 13 | MSG_STATE = "Баланс: {balance}" 14 | 15 | HEADERS = { 16 | "sec-ch-ua": 'Chromium";v="122", "Not(A:Brand";v="24", "Android WebView";v="122', 17 | "sec-ch-ua-mobile": "?1" , 18 | "sec-ch-ua-platform": "Android", 19 | "upgrade-insecure-requests": "1" , 20 | "user-agent": "Mozilla/5.0 (Linux; Android 11; Redmi 5 Plus Build/RQ3A.210805.001.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.64 Mobile Safari/537.36" , 21 | "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7" , 22 | "x-requested-with": "org.telegram.messenger" , 23 | "sec-fetch-site": "none" , 24 | "sec-fetch-mode": "navigate" , 25 | "sec-fetch-user": "?1" , 26 | "sec-fetch-dest": "document" , 27 | "accept-language": "ru,ru-RU;q=0.9,en-US;q=0.8,en;q=0.7", 28 | "Authorization": "Bearer", 29 | "Anon-Auth": None 30 | } 31 | 32 | -------------------------------------------------------------------------------- /bots/base/DEV_GUIDE.md: -------------------------------------------------------------------------------- 1 | ### Что хочется видеть: 2 | У каждого модуля должна быть похожая структура: 3 | 4 | ``` 5 | __init__.py 6 | client.py 7 | utils.py 8 | strings.py 9 | ``` 10 | `__init__.py` - Инициализация пакета. Достаточно оставить файл пустым 11 | 12 | `utils.py` - Опционален, здесь размещаем вспомогательные функции для работы модуля. Парсеры, конвертеры и т.д. 13 | 14 | `strings.py` - Здесь храним все URL, строки сообщений, словари с данными. Большая просьба не размещать в самом коде строки в чистом виде. Гораздо приятнее видеть константы, редактировать их тоже удобнее в отдельном файле. 15 | 16 | `client.py` - Ну а это сердце нашего модуля. Здесь и будет наш класс фармера. В этом файле обязательно описать класс `BotFarmer`. Именно он и будет импортироваться в фабрику при старте. 17 | 18 | ### Разработка 19 | Для удобства разработки я сделал модуль-болванку и поместил в каталог `bots/template`: 20 | 21 | ```python 22 | from bots.base.base import BaseFarmer 23 | from bots.template.strings import HEADERS 24 | 25 | 26 | class BotFarmer(BaseFarmer): 27 | name = "bot_username" 28 | extra_code = "ref_code" # в случае если рефка вида https://t.me/bot_username?start=ref_code 29 | app_extra = "ref_code" # в случае если рефка вида https://t.me/bot_username?action?param=ref_code (Это нужно доработать, но примеры есть среди ботов) 30 | initialization_data = {} # данные для передачи в инициатор, отличаются в зависимости от типа кнопки входа в бота 31 | refreshable_token = False # обновлять ли токен в боте 32 | codes_to_refresh = (401,) # при получении этих статусов будет автоматически обновляться токен вызовом self.refresh_token() 33 | 34 | 35 | def set_headers(self, *args, **kwargs): 36 | """ Установка заголовков """ 37 | self.headers = HEADERS.copy() 38 | 39 | def authenticate(self, *args, **kwargs): 40 | """ Аутентифифкация, получения токена, выставление заголовков, заполнение шаблона запроса и тд... """ 41 | raise NotImplementedError 42 | 43 | def refresh_token(self): 44 | """ Метод вызывается для обновления токена, при условии что self.refreshable_token == True """ 45 | raise NotImplementedError 46 | 47 | def set_start_time(self): 48 | """ 49 | Метод выставляет время следующего захода фармера. 50 | Например время когда закончится фарминг или накопятся тапы 51 | Время выставляется в формате timestamp 52 | time.time() + 60 это запуск через минуту 53 | """ 54 | raise NotImplementedError 55 | 56 | def farm(self): 57 | """ 58 | Основной метод, описывающий логику модуля. 59 | Покупки, прокачки. Все здесь 60 | """ 61 | raise NotImplementedError 62 | ``` 63 | 64 | Для начала работ копируем каталог `template` и переименовываем в новый модуль. 65 | 66 | # ... 67 | -------------------------------------------------------------------------------- /bots/base/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TotalAwesome/BotFarmFactory/a014a70f66abbe1a46c9796847cd8813764978d1/bots/base/__init__.py -------------------------------------------------------------------------------- /bots/base/base.py: -------------------------------------------------------------------------------- 1 | 2 | from time import time 3 | from datetime import datetime 4 | from random import choice 5 | from requests import Session 6 | from .utils import check_proxy, retry, logging, debug_logger 7 | from .strings import USER_AGENTS, LOG_TEMPLATE, MSG_PROXY_CONNECTION_ERROR 8 | from config import DEBUG, SLEEP_AT_NIGHT, NIGHT_HOURS 9 | 10 | 11 | class BaseFarmer(Session): 12 | 13 | """ 14 | Базовый класс 15 | У дочерних классов реализовать методы: 16 | set_headers -> Установка заголовков 17 | authenticate -> Аутентификация и рефреш если надо 18 | farm -> Выполнение всех необходимых действий с аккаунтом за один прогон 19 | set_start_time -> Таймштамп следующего прогона 20 | refresh_token -> Если нужен рефреш 21 | """ 22 | 23 | name = None # bot_username 24 | initiator = None 25 | initialization_data = {} 26 | account_name = None 27 | start_time = time() 28 | codes_to_refresh = tuple() 29 | refreshable_token = False 30 | extra_code = None 31 | app_extra = None 32 | is_alive = True 33 | ip = None 34 | debug = True 35 | 36 | def __init__(self, initiator, proxy=None, only_proxy=False, **kwargs) -> None: 37 | super().__init__() 38 | self.features = kwargs 39 | self.set_headers() 40 | self.update_user_agent() 41 | self.initiator = initiator 42 | self.get_account_name() 43 | if proxy: 44 | proxies = dict(http=proxy, https=proxy) 45 | if ip := check_proxy(proxies): 46 | self.ip = ip 47 | self.proxies = proxies 48 | elif only_proxy: 49 | raise Exception(MSG_PROXY_CONNECTION_ERROR.format(str(kwargs))) 50 | if self.extra_code: 51 | self.initiator.prepare_bot(self.name, self.name, self.extra_code) 52 | self.authenticate() 53 | self.initiator.prepare_bot(self.name, self.name, self.extra_code or self.app_extra) 54 | 55 | def log(self, message, error=False, debug=False): 56 | ip = self.ip if self.ip else "no_proxy" 57 | if not error and not debug: 58 | log_method = logging.info 59 | elif error: 60 | log_method = logging.error 61 | else: 62 | log_method = debug_logger.debug 63 | msg = LOG_TEMPLATE.format(farmer_name=self.name.lower(), 64 | user=self.account_name, 65 | message=message, 66 | ip=ip) 67 | log_method(msg) 68 | 69 | def error(self, message): 70 | self.log(message=message, error=True) 71 | 72 | def debug(self, message): 73 | self.log(message=message, debug=True) 74 | 75 | @retry 76 | def request(self, *args, **kwargs): 77 | response = super().request(*args, **kwargs) 78 | if DEBUG and self.debug: 79 | self.debug(f"request {args}, {kwargs}") 80 | self.debug(f"response {response.status_code}, {response.text}") 81 | return response 82 | 83 | def get_account_name(self): 84 | me = self.initiator.get_me() 85 | self.account_name = me.username or me.first_name or me.phone 86 | 87 | @property 88 | def is_ready_to_farm(self): 89 | if SLEEP_AT_NIGHT and datetime.now().hour in range(*NIGHT_HOURS): 90 | return False 91 | return self.start_time <= time() 92 | 93 | def set_start_time(self): 94 | self.start_time = time() + 10 * 60 95 | 96 | def set_headers(self, *args, **kwargs): 97 | self.update_user_agent() 98 | 99 | def update_user_agent(self): 100 | user_agent_header = 'user-agent' 101 | for header in self.headers: 102 | if header.lower() == 'user-agent': 103 | user_agent_header = header 104 | break 105 | self.headers[user_agent_header] = choice(USER_AGENTS) 106 | 107 | def authenticate(self, *args, **kwargs): 108 | raise NotImplementedError 109 | 110 | def refresh_token(self, *args, **kwargs): 111 | raise NotImplementedError 112 | 113 | def farm(self): 114 | raise NotImplementedError 115 | 116 | def proceed_farming(self): 117 | if self.is_alive and self.is_ready_to_farm: 118 | try: 119 | self.farm() 120 | self.set_start_time() 121 | except Exception as err: 122 | self.error(err) 123 | self.start_time = time() + 60 * 60 124 | self.log('Следующий заход в : {}'.format( 125 | datetime.fromtimestamp(self.start_time).strftime('%d-%m-%Y %H:%M:%S') 126 | )) 127 | -------------------------------------------------------------------------------- /bots/base/strings.py: -------------------------------------------------------------------------------- 1 | URL_CHECK_IP = 'https://httpbin.org/ip' 2 | MSG_PROXY_IP = "Прокси работает. Ваш IP через прокси: {ip}" 3 | MSG_PROXY_CHECK_ERROR = "Ошибка при проверке прокси. Код ответа: {status_code}" 4 | MSG_PROXY_CONNECTION_ERROR = "Не удалось подключиться через прокси: {error}" 5 | MSG_BAD_RESPONSE = "Плохой ответ от сервера: {status}. Текст ответа в debug.log" 6 | MSG_SESSION_ERROR = "Ошибка во время выполнения запроса: {error}" 7 | MSG_FAILED_REQUEST = "Не получилось выполнить запрос. Подождем..." 8 | BASE_NAME = 'BaseFarmer' 9 | 10 | 11 | USER_AGENTS = [ 12 | "Mozilla/5.0 (Linux; Android 15.1; X96Q_PRO2 Build/QP1A.191105.004; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/80.0.3987.149 Mobile Safari/537.36", 13 | "Mozilla/5.0 (Linux; Android 11.3; YD206 Build/P1NKL07U5) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/101.0.4951.54 Mobile Safari/537.36 Android 11.3", 14 | "Mozilla/5.0 (Linux; Android 12.1; SM-G998U Build/RP1A.200720.012; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/64.0.3282.116 Mobile Safari/537.36", 15 | "Mozilla/5.0 (Linux; Android 12.1; SM-G996W Build/PPR1.180610.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/64.0.3282.116 Mobile Safari/537.36", 16 | "Mozilla/5.0 (Linux; Android 12.0.1; zh-cn; Pixel 6 Pro; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/98.0.4758.46 Mobile Safari/537.36 SearchCraft/3.7.0 (Baidu; P1 9)", 17 | "Mozilla/5.0 (Linux; Android 11; Android SDK built for x86_64 Build/RSR1.210722.012; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/83.0.4103.120 Mobile Safari/537.36", 18 | "Mozilla/5.0 (Linux; Android 13; Pixel 4a Build/TQ3A.230805.001.S1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/124.0.6367.179 Mobile Safari/537.36 App Version:4.0.9.3", 19 | "Mozilla/5.0 (Linux; Android 13; CPH2251 Build/TP1A.220905.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/126.0.6478.26 Mobile Safari/537.36", 20 | "Mozilla/5.0 (Linux; Android 13; SM-A715W Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/111.0.5563.116 Mobile Safari/537.36", 21 | "Mozilla/5.0 (Linux; Android 13; V2322; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/87.0.4280.141 Mobile Safari/537.36 VivoBrowser/12.3.2.3", 22 | ] 23 | 24 | LOG_TEMPLATE = "[ {user} | {ip} | {farmer_name} ] >> {message}" -------------------------------------------------------------------------------- /bots/base/utils.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from .strings import URL_CHECK_IP, MSG_BAD_RESPONSE, MSG_PROXY_CHECK_ERROR, MSG_PROXY_CONNECTION_ERROR, \ 3 | MSG_PROXY_IP, MSG_SESSION_ERROR, MSG_FAILED_REQUEST 4 | from config import RETRY_ATTEMPTS 5 | from time import sleep 6 | from requests import get as requests_get 7 | from dateutil import tz, parser 8 | 9 | log_format = "%(asctime)s %(levelname)s %(message)s" 10 | logging.basicConfig(level=logging.INFO, format=log_format, datefmt='%Y-%m-%d %H:%M:%S') 11 | formatter = logging.Formatter(log_format) 12 | 13 | file_handler = logging.FileHandler('debug.log', encoding='utf-8') 14 | file_handler.setLevel(logging.DEBUG) 15 | file_handler.setFormatter(formatter) 16 | 17 | debug_logger = logging.getLogger("debug_logger") 18 | debug_logger.propagate = False 19 | debug_logger.setLevel(logging.DEBUG) 20 | debug_logger.addHandler(file_handler) 21 | 22 | 23 | def check_proxy(proxies): 24 | try: 25 | response = requests_get(URL_CHECK_IP, proxies=proxies) 26 | if response.status_code == 200: 27 | ip = response.json()['origin'] 28 | logging.info(MSG_PROXY_IP.format(ip=ip)) 29 | return ip 30 | else: 31 | logging.error(MSG_PROXY_CHECK_ERROR.format(status_code=response.status_code)) 32 | except Exception as error: 33 | logging.error(MSG_PROXY_CONNECTION_ERROR.format(error=error)) 34 | 35 | 36 | def retry(func): 37 | def wrapper(*args, **kwargs): 38 | self = args[0] 39 | attempts = 0 40 | return_codes = kwargs.pop('return_codes', tuple()) 41 | while attempts <= RETRY_ATTEMPTS: 42 | try: 43 | result = func(*args, **kwargs) 44 | if result.status_code in return_codes: 45 | return result 46 | if result.status_code not in (200, 201, 202): 47 | if result.status_code == 429: 48 | self.log(MSG_BAD_RESPONSE.format(status=result.status_code)) 49 | sleep(10) 50 | attempts += 1 51 | continue 52 | elif result.status_code in self.codes_to_refresh and self.refreshable_token: 53 | self.refresh_token() 54 | attempts += 1 55 | continue 56 | # elif result.status_code in (401, 403): 57 | else: 58 | self.log(MSG_BAD_RESPONSE.format(status=result.status_code)) 59 | raise Exception(f"code: {result.status_code} {result.text}") 60 | return result 61 | except Exception as error: 62 | self.log(MSG_SESSION_ERROR.format(error=error)) 63 | attempts += 1 64 | sleep(3) 65 | raise Exception(MSG_FAILED_REQUEST) 66 | return wrapper 67 | 68 | 69 | def to_localtz_timestamp(zulutime: str): 70 | return parser.parse(zulutime).astimezone(tz.tzlocal()).timestamp() 71 | 72 | 73 | def api_response(func): 74 | def wrapper(*args, **kwargs): 75 | response = func(*args, **kwargs) 76 | if response.status_code in (200, 201): 77 | return response.json() if response.text else {"ok": True} # Костыль, если вернуло 200 и пустое тело 78 | else: 79 | return {} 80 | return wrapper 81 | 82 | -------------------------------------------------------------------------------- /bots/blum/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TotalAwesome/BotFarmFactory/a014a70f66abbe1a46c9796847cd8813764978d1/bots/blum/__init__.py -------------------------------------------------------------------------------- /bots/blum/client.py: -------------------------------------------------------------------------------- 1 | import json 2 | from random import randrange, choice, random 3 | from time import sleep, time 4 | from telethon.types import InputBotAppShortName 5 | from bots.base.base import BaseFarmer 6 | from bots.blum.strings import HEADERS, URL_REFRESH_TOKEN, URL_BALANCE, URL_TASKS, \ 7 | URL_WEBAPP_INIT, URL_AUTH, URL_FARMING_CLAIM, URL_FARMING_START, URL_PLAY_START, \ 8 | URL_PLAY_CLAIM, URL_DAILY_REWARD, URL_FRIENDS_BALANCE, URL_FRIENDS_CLAIM, MSG_AUTH, \ 9 | MSG_REFRESH, MSG_BALANCE_UPDATE, MSG_START_FARMING, MSG_CLAIM_FARM, MSG_BEGIN_GAME, MSG_GAME_OFF, \ 10 | MSG_PLAYED_GAME, MSG_DAILY_REWARD, MSG_FRIENDS_CLAIM, URL_CHECK_NAME, MSG_INPUT_USERNAME, \ 11 | URL_TASK_CLAIM, URL_TASK_START, MSG_TASK_CLAIMED, MSG_TASK_STARTED, MSG_BALANCE_INFO 12 | from bots.blum.config import MANUAL_USERNAME, GAME_TOGGLE_ON 13 | 14 | GAME_RESULT_RANGE = (190, 280) 15 | DEFAULT_EST_TIME = 60 16 | 17 | 18 | class BotFarmer(BaseFarmer): 19 | 20 | name = "BlumCryptoBot" 21 | app_extra = "ref_ItXoLRFElL" 22 | balance = None 23 | balance_data = None 24 | play_passes = None 25 | tasks = None 26 | auth_data = None 27 | codes_to_refresh = (401,) 28 | refreshable_token = True 29 | 30 | @property 31 | def initialization_data(self): 32 | return dict(peer=self.name, 33 | app=InputBotAppShortName(self.initiator.get_input_entity(self.name), "app"), 34 | start_param=self.app_extra) 35 | 36 | def check_name(self, username): 37 | response = self.post(URL_CHECK_NAME, json={'username': username}, return_codes=(400, 409)) 38 | return response.status_code == 200 39 | 40 | def set_headers(self, *args, **kwargs): 41 | self.headers = HEADERS.copy() 42 | 43 | def set_start_time(self): 44 | if 'farming' in self.balance_data: 45 | est_time = (self.balance_data['farming']['endTime'] - self.balance_data['timestamp']) / 1000 + 1 46 | est_time = est_time if est_time > 0 else DEFAULT_EST_TIME 47 | else: 48 | est_time = DEFAULT_EST_TIME 49 | self.start_time = time() + est_time 50 | 51 | def authenticate(self): 52 | if not self.auth_data: 53 | self.log(MSG_AUTH) 54 | init_data = self.initiator.get_auth_data(**self.initialization_data) 55 | result = self.post(URL_AUTH, json={"query": init_data["authData"]}) 56 | if result.status_code == 200: 57 | self.auth_data = result.json().get('token') 58 | if not self.auth_data: 59 | if not self.create_account_and_get_token(init_data=init_data["authData"]): 60 | return 61 | self.headers['Authorization'] = f"Bearer {self.auth_data['access']}" 62 | 63 | def create_account_and_get_token(self, init_data): 64 | if not MANUAL_USERNAME: 65 | import string 66 | charmap = string.ascii_letters + '_' 67 | while True: 68 | if not MANUAL_USERNAME: 69 | username = ''.join(str(choice(charmap)) for _ in range(randrange(6, 12))) 70 | else: 71 | username = input(MSG_INPUT_USERNAME) 72 | if self.check_name(username=username): 73 | payload = dict(query=init_data, 74 | referralToken=self.app_extra.split('_')[-1], 75 | username=username) 76 | result = self.post(URL_AUTH, json=payload) 77 | else: 78 | continue 79 | if result.status_code == 200: 80 | self.auth_data = result.json().get('token') 81 | if not self.auth_data: 82 | self.error("Blum не зарегистрирован по реф. ссылке") 83 | self.is_alive = False 84 | return 85 | return True 86 | sleep(5) 87 | 88 | 89 | def refresh_token(self): 90 | self.log(MSG_REFRESH) 91 | self.headers.pop('Authorization') 92 | result = self.post(URL_REFRESH_TOKEN, json={"refresh": self.auth_data['refresh']}) 93 | if result.status_code == 200: 94 | self.auth_data = result.json() 95 | self.headers['Authorization'] = f"Bearer {self.auth_data['access']}" 96 | 97 | 98 | def update_tasks(self): 99 | response = self.get(URL_TASKS) 100 | if response.status_code == 200: 101 | result = response.json() 102 | self.tasks = [] 103 | for item in result: 104 | if task_group := item["tasks"]: 105 | self.tasks = self.tasks + task_group 106 | 107 | @property 108 | def estimate_time(self): 109 | if 'farming' in self.balance_data: 110 | est_time = (self.balance_data['farming']['endTime'] - self.balance_data['timestamp']) / 1000 + 1 111 | return est_time if est_time > 0 else DEFAULT_EST_TIME 112 | else: 113 | return DEFAULT_EST_TIME 114 | 115 | def update_balance(self, log_info=False): 116 | if log_info: 117 | self.log(MSG_BALANCE_UPDATE) 118 | response = self.get(URL_BALANCE, headers=self.headers) 119 | if response.status_code == 200: 120 | self.balance_data = response.json() 121 | self.balance = self.balance_data['availableBalance'] 122 | self.play_passes = self.balance_data['playPasses'] 123 | 124 | def check_tasks(self): 125 | self.update_tasks() 126 | for task in self.tasks: 127 | if task['type'] == 'SOCIAL_SUBSCRIPTION' and task['status'] == "NOT_STARTED": 128 | response = self.post(URL_TASK_START.format(**task)) 129 | if response.status_code == 200: 130 | self.log(MSG_TASK_STARTED.format(**task)) 131 | task.update(response.json()) 132 | sleep(random() * 5) 133 | if task['status'] == "READY_FOR_CLAIM": 134 | response = self.post(URL_TASK_CLAIM.format(**task)) 135 | if response.status_code == 200: 136 | self.log(MSG_TASK_CLAIMED.format(**task)) 137 | task.update(response.json()) 138 | sleep(random() * 5) 139 | 140 | def start_farming(self): 141 | if 'farming' not in self.balance_data: 142 | self.log(MSG_START_FARMING) 143 | result = self.post(URL_FARMING_START) 144 | self.update_balance() 145 | elif self.balance_data["timestamp"] >= self.balance_data["farming"]["endTime"]: 146 | result = self.post(URL_FARMING_CLAIM) 147 | self.log(MSG_CLAIM_FARM.format(amount=self.balance_data["farming"]["balance"])) 148 | self.log(MSG_BALANCE_INFO.format(balance=self.balance, 149 | play_passes=self.play_passes)) 150 | 151 | def play_game(self): 152 | if not GAME_TOGGLE_ON: 153 | self.log(MSG_GAME_OFF) 154 | return 155 | else: 156 | for _ in range(self.play_passes or 0): 157 | self.log(MSG_BEGIN_GAME.format(self.play_passes)) 158 | res = self.post(URL_PLAY_START) 159 | if res.status_code == 200: 160 | data = res.json() 161 | data['points'] = int(randrange(*GAME_RESULT_RANGE)) 162 | sleep(30) 163 | while True: 164 | result = self.post(URL_PLAY_CLAIM, json=data) 165 | if result.status_code == 200: 166 | break 167 | else: 168 | sleep(1) 169 | self.log(MSG_PLAYED_GAME.format(result=data['points'])) 170 | self.update_balance() 171 | 172 | def daily_reward(self): 173 | result = self.get(URL_DAILY_REWARD, return_codes=(404,)) 174 | if result.status_code == 200: 175 | self.post(URL_DAILY_REWARD) 176 | {"ordinal":31,"reward":{"passes":7,"points":"70"}} 177 | msg_data = result.json()['days'][-1] 178 | self.log(MSG_DAILY_REWARD.format(days=msg_data['ordinal'], 179 | passes=msg_data['reward']['passes'], 180 | points=msg_data['reward']['points'])) 181 | 182 | def friends_claim(self): 183 | friends_balance = self.get(URL_FRIENDS_BALANCE) 184 | if friends_balance.status_code == 200: 185 | if friends_balance.json().get('canClaim'): 186 | result = self.post(URL_FRIENDS_CLAIM) 187 | if result.status_code == 200: 188 | self.log(MSG_FRIENDS_CLAIM.format(points=result.json()['claimBalance'])) 189 | 190 | def farm(self): 191 | self.daily_reward() 192 | self.friends_claim() 193 | self.update_balance(log_info=True) 194 | self.play_game() 195 | self.start_farming() 196 | self.check_tasks() -------------------------------------------------------------------------------- /bots/blum/config.py: -------------------------------------------------------------------------------- 1 | MANUAL_USERNAME = False 2 | GAME_TOGGLE_ON = True # По умолчанию играть в мини-игру звездочки - True, пропускать - False -------------------------------------------------------------------------------- /bots/blum/strings.py: -------------------------------------------------------------------------------- 1 | URL_WEBAPP_INIT = "https://telegram.blum.codes/" 2 | URL_ME = "https://gateway.blum.codes/v1/user/me" 3 | URL_NOW = "https://game-domain.blum.codes/api/v1/time/now" 4 | URL_AUTH = "https://gateway.blum.codes/v1/auth/provider/PROVIDER_TELEGRAM_MINI_APP" 5 | URL_REFRESH_TOKEN = "https://gateway.blum.codes/v1/auth/refresh" 6 | URL_BALANCE = "https://game-domain.blum.codes/api/v1/user/balance" 7 | URL_TASKS = "https://game-domain.blum.codes/api/v1/tasks" 8 | URL_TASK_START = "https://game-domain.blum.codes/api/v1/tasks/{id}/start" 9 | URL_TASK_CLAIM = "https://game-domain.blum.codes/api/v1/tasks/{id}/claim" 10 | URL_FARMING_CLAIM = "https://game-domain.blum.codes/api/v1/farming/claim" 11 | URL_FARMING_START = "https://game-domain.blum.codes/api/v1/farming/start" 12 | URL_PLAY_START = "https://game-domain.blum.codes/api/v1/game/play" 13 | URL_PLAY_CLAIM = "https://game-domain.blum.codes/api/v1/game/claim" 14 | URL_DAILY_REWARD = "https://game-domain.blum.codes/api/v1/daily-reward?offset=-180" 15 | URL_FRIENDS_BALANCE = "https://gateway.blum.codes/v1/friends/balance" 16 | URL_FRIENDS_CLAIM = "https://gateway.blum.codes/v1/friends/claim" 17 | URL_CHECK_NAME = "https://gateway.blum.codes/v1/user/username/check" 18 | 19 | MSG_AUTH = "Получение токена" 20 | MSG_REFRESH = "Обновление токена" 21 | MSG_BALANCE_UPDATE = "Обновление баланса" 22 | MSG_BALANCE_INFO = "Баланс: {balance} Количество игр: {play_passes}" 23 | MSG_START_FARMING = "Начал фармить" 24 | MSG_CLAIM_FARM = "Собрал нафармленное: {amount}" 25 | MSG_FARMING_WAIT = "Ожидание завершения фарминга {} секунд" 26 | MSG_BEGIN_GAME = "Начинаем тапать звездочки. Количество игр: {})" 27 | MSG_PLAYED_GAME = "Натапал: {result}" 28 | MSG_GAME_OFF = "Мини-игра в звездочки отключена" 29 | MSG_DAILY_REWARD = "Ежедневная награда. День: {days} игры: {passes} монеты: {points}" 30 | MSG_FRIENDS_CLAIM = "Друзья нафармили: {points}" 31 | MSG_INPUT_USERNAME = "Введи имя для Blum: " 32 | MSG_TASK_STARTED = "Начал выполнять таску {title}" 33 | MSG_TASK_CLAIMED = "Выполнил таску {title} на {reward} монет" 34 | 35 | HEADERS = { 36 | "Accept": 'application/json', 37 | "Accept-Encoding": 'gzip, deflate, br, zstd', 38 | "Accept-Language": 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7', 39 | 'Cache-Control': 'no-cache', 40 | "Origin": 'https://telegram.blum.codes', 41 | "Referer": 'https://telegram.blum.codes/', 42 | "Sec-Ch-Ua-Mobile": '?1', 43 | "Sec-Ch-Ua-Platform": 'Android"', 44 | "User-Agent": 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 45 | } 46 | 47 | TOKEN_FILE = "token.json" 48 | 49 | 50 | -------------------------------------------------------------------------------- /bots/cell/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TotalAwesome/BotFarmFactory/a014a70f66abbe1a46c9796847cd8813764978d1/bots/cell/__init__.py -------------------------------------------------------------------------------- /bots/cell/client.py: -------------------------------------------------------------------------------- 1 | from random import random 2 | from telethon.types import InputBotAppShortName 3 | from bots.base.base import BaseFarmer, time 4 | from bots.base.utils import to_localtz_timestamp 5 | 6 | from bots.cell.strings import HEADERS, URL_PROFILE, URL_CLAIM, URL_TAP, MSG_CLAIM, MSG_PROFILE_UPDATE, \ 7 | MSG_STATE, MSG_TAP, URL_LEVELS, MSG_LEVELS_UPDATE, URL_UPGRADE_LEVEL, MSG_BONUS 8 | 9 | 10 | class BotFarmer(BaseFarmer): 11 | 12 | name = 'cellcoin_bot' 13 | upgrades = {} 14 | info = {} 15 | levels = {} 16 | next_claim = None 17 | extra_code = "102796269" 18 | 19 | @property 20 | def initialization_data(self): 21 | return dict(peer=self.name, 22 | app=InputBotAppShortName(self.initiator.get_input_entity(self.name), "app"), 23 | start_param='') 24 | 25 | def set_headers(self, *args, **kwargs): 26 | self.headers = HEADERS.copy() 27 | 28 | def authenticate(self, *args, **kwargs): 29 | auth_data = self.initiator.get_auth_data(**self.initialization_data)['authData'] 30 | self.headers['Authorization'] = auth_data[auth_data.index('user'):] 31 | 32 | def api_call(self, url, post=True, json=None): 33 | method = self.post if post else self.get 34 | kwargs = dict(url=url, return_codes=(400,)) 35 | if post: 36 | kwargs['json'] = json 37 | response = method(**kwargs) 38 | if response.status_code == 200: 39 | return response.json() 40 | else: 41 | return {} 42 | 43 | @property 44 | def energy_max(self): 45 | level = str(self.info['energy_level']) 46 | return self.levels['cell_energy_levels_map'][level]['capacity'] 47 | 48 | def update_profile(self): 49 | self.info = self.api_call(URL_PROFILE, post=False).get("cell", {}) 50 | self.log(MSG_PROFILE_UPDATE) 51 | 52 | def update_levels(self): 53 | self.levels = self.api_call(URL_LEVELS, post=False) 54 | self.log(MSG_LEVELS_UPDATE) 55 | 56 | def set_start_time(self): 57 | taps_recover_seconds = self.energy_max 58 | self.start_time = time() + taps_recover_seconds 59 | 60 | def tap(self): 61 | self.update_profile() 62 | balance = self.info['balance'] 63 | self.info = self.api_call(URL_TAP, json={"clicks_amount": 1})['cell'] 64 | if energy := self.info.get("energy_amount"): 65 | self.info = self.api_call(URL_TAP, json={"clicks_amount": energy})['cell'] 66 | self.log(MSG_TAP.format(taps=energy)) 67 | 68 | def claim(self): 69 | self.update_profile() 70 | if not self.next_claim or self.next_claim <= time(): 71 | balance = self.info['balance'] 72 | if response := self.api_call(URL_CLAIM): 73 | self.info = response['cell'] 74 | diff = self.info['balance'] - balance 75 | self.next_claim = time() + 60 * 12 * self.info['storage_level'] + random() * 10 76 | self.log(MSG_CLAIM.format(amount=diff / 1_000_000)) 77 | 78 | 79 | def daily_reward(self): 80 | if to_localtz_timestamp(self.info.get('bonus_claimed_at')) + 86401 < time(): 81 | self.api_call(URL_UPGRADE_LEVEL, json={"level_type":"bonus"}, post=True) 82 | self.log(MSG_BONUS) 83 | 84 | 85 | def farm(self): 86 | self.update_levels() 87 | self.tap() 88 | self.claim() 89 | self.daily_reward() 90 | self.log(MSG_STATE.format(balance=self.info['balance'] / 1_000_000)) 91 | 92 | -------------------------------------------------------------------------------- /bots/cell/strings.py: -------------------------------------------------------------------------------- 1 | URL_INIT = "https://cell-frontend.s3.us-east-1.amazonaws.com/telegram-mini-app/index.html" 2 | URL_PROFILE = "https://cellcoin.org/users/session" # POST 3 | URL_TAP = "https://cellcoin.org/cells/submit_clicks" # POST {userid, authdata, count} 4 | URL_CLAIM = "https://cellcoin.org/cells/claim_storage" 5 | URL_LEVELS = "https://cellcoin.org/cells/levels" 6 | URL_UPGRADE_LEVEL = "https://cellcoin.org/cells/levels/upgrade" # POST {"level_type":"bonus"} 7 | 8 | MSG_PROFILE_UPDATE = "Обновление профиля" 9 | MSG_LEVELS_UPDATE = "Обновление уровней" 10 | MSG_TAP = "Натапал {taps} монет" 11 | MSG_CLAIM = "Собрал нафармленное: {amount}" 12 | MSG_STATE = "Баланс: {balance}" 13 | MSG_BONUS = "Получил бонус" 14 | 15 | HEADERS = { 16 | 'sec-ch-ua': 'Chromium";v="122", "Not(A:Brand";v="24", "Android WebView";v="122', 17 | 'sec-ch-ua-mobile': '?1', 18 | 'user-agent': 'Mozilla/5.0 (Linux; Android 11; Redmi 10 Build/RQ3A.156515.001.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.64 Mobile Safari/537.36', 19 | 'sec-ch-ua-platform': 'Android', 20 | 'Accept': '*/*', 21 | 'Origin': 'https://cell-frontend.s3.us-east-1.amazonaws.com', 22 | 'Referer': 'https://cell-frontend.s3.us-east-1.amazonaws.com', 23 | 'X-Requested-With': 'org.telegram.messenger', 24 | 'Sec-Fetch-Site': 'cross-site', 25 | 'Sec-Fetch-Mode': 'cors', 26 | 'Sec-Fetch-Dest': 'empty', 27 | } 28 | -------------------------------------------------------------------------------- /bots/cell/utils.py: -------------------------------------------------------------------------------- 1 | 2 | from datetime import datetime, timedelta 3 | from tzlocal import get_localzone 4 | 5 | 6 | def convert_datetime(utc_time): 7 | utc_time = "2024-06-19T20:34:17.354Z" 8 | raw = datetime.strptime(utc_time, "%Y-%m-%dT%H:%M:%S.%fZ").astimezone(tz="UTC") -------------------------------------------------------------------------------- /bots/dogs/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /bots/dogs/client.py: -------------------------------------------------------------------------------- 1 | """ 2 | Author: Eyn 3 | Date: 24-07-2024 4 | 5 | """ 6 | from random import randrange 7 | from time import time, sleep 8 | 9 | from bots.base.base import BaseFarmer 10 | from bots.dogs.strings import HEADERS, URL_INIT, URL_LOGIN, MSG_CURRENT_BALANCE, \ 11 | MSG_CURRENT_FRIENDS, URL_FRIENDS, MSG_LOGIN_ERROR, URL_GET_TASKS, URL_VERIFY_TASK, MSG_TASK_COMPLETE, \ 12 | MSG_TASK_ERROR 13 | from bots.dogs.config import TASK_EXCLUDE 14 | 15 | DEFAULT_EST_TIME = 60 * 10 16 | LOGIN_RANGE = (100, 1300) 17 | 18 | 19 | class BotFarmer(BaseFarmer): 20 | name = "dogshouse_bot" 21 | balance = None 22 | user_id = None 23 | ref_code = None 24 | auth_data = None 25 | extra_code = '07wokQJZTrS5FSrah8SigQ' 26 | initialization_data = dict(peer=name, bot=name, url=URL_INIT, start_param=extra_code) 27 | 28 | def set_headers(self, *args, **kwargs): 29 | self.headers = HEADERS.copy() 30 | 31 | def authenticate(self, *args, **kwargs): 32 | try: 33 | 34 | init_data = self.initiator.get_auth_data(**self.initialization_data) 35 | self.auth_data = init_data['authData'] 36 | login_url = URL_LOGIN + '?' + 'invite_hash=' + self.extra_code 37 | 38 | result = self.post(login_url, data=self.auth_data) 39 | 40 | if result.status_code == 200: 41 | self.handle_successful_login(result.json()) 42 | except Exception as e: 43 | self.log(MSG_LOGIN_ERROR.format(e=e)) 44 | self.is_alive = False 45 | 46 | def handle_successful_login(self, json_data): 47 | user_data = json_data 48 | self.balance = user_data['balance'] 49 | self.ref_code = user_data['reference'] 50 | self.user_id = user_data['telegram_id'] 51 | self.is_alive = True 52 | 53 | def set_start_time(self): 54 | max_time = 23 * 3600 55 | random_time = randrange(DEFAULT_EST_TIME, max_time) 56 | self.start_time = time() + random_time 57 | 58 | def show_balance(self): 59 | self.log(MSG_CURRENT_BALANCE.format(balance=self.balance)) 60 | 61 | def show_friends(self): 62 | url = URL_FRIENDS + f'?user_id={self.user_id}&reference={self.ref_code}' 63 | response = self.get(url) 64 | response_json = response.json() 65 | self.log(MSG_CURRENT_FRIENDS.format(total=response_json['count'])) 66 | 67 | def process_tasks(self): 68 | response = self.get(URL_GET_TASKS.format(user_id=self.user_id, reference=self.ref_code)).json() 69 | 70 | for task in response: 71 | if (not task['complete']) and (task["slug"] not in TASK_EXCLUDE): 72 | sleep(randrange(4, 7)) 73 | self.process_task(task) 74 | 75 | def process_task(self, task): 76 | try: 77 | response = self.post( 78 | URL_VERIFY_TASK.format(slug=task['slug'], user_id=self.user_id, reference=self.ref_code)).json() 79 | if response['success']: 80 | self.log(MSG_TASK_COMPLETE.format(slug=task['slug'], reward=task['reward'])) 81 | else: 82 | self.log(MSG_TASK_ERROR.format(slug=task['slug'])) 83 | except Exception as e: 84 | self.log(MSG_TASK_ERROR.format(slug=task['slug'])) 85 | 86 | def farm(self): 87 | self.show_balance() 88 | self.show_friends() 89 | self.process_tasks() 90 | 91 | -------------------------------------------------------------------------------- /bots/dogs/config.py: -------------------------------------------------------------------------------- 1 | try: 2 | from bots.dogs.config_local import TASK_EXCLUDE 3 | except: 4 | TASK_EXCLUDE = [] 5 | 6 | 7 | ''' 8 | 9 | Последовательность действий: 10 | 1. Создайте файл config_local.py 11 | 2. Пример содержимого: 12 | 13 | TASK_EXCLUDE = [ 14 | "notcoin-tier-gold", 15 | "notcoin-tier-platinum", 16 | "add-bone-telegram", 17 | "invite-frens", 18 | "subscribe-notcoin", 19 | ] 20 | 21 | В результате, ваш конфиг не будет перезатираться при обновлении фабрики. 22 | Можете добавлять/убирать по аналогии таски, которые бот не может выполнить. 23 | Название таска берем из сообщения в логе, например: "...Ошибка задания invite-frens" 24 | invite-frens - название таска. 25 | 26 | ''' -------------------------------------------------------------------------------- /bots/dogs/strings.py: -------------------------------------------------------------------------------- 1 | URL_INIT = 'https://onetime.dog/' 2 | URL_LOGIN = 'https://api.onetime.dog/join' 3 | URL_FRIENDS = 'https://api.onetime.dog/frens' 4 | URL_GET_TASKS = 'https://api.onetime.dog/tasks?user_id={user_id}&reference={reference}' 5 | URL_VERIFY_TASK = 'https://api.onetime.dog/tasks/verify?task={slug}&user_id={user_id}&reference={reference}' 6 | 7 | HEADERS = { 8 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 9 | 'Accept-Encoding': 'gzip, deflate, br, zstd', 10 | 'Accept-Language': 'en-US,en;q=0.9', 11 | 'Dnt': '1', 12 | 'Referer': 'https://onetime.dog/', 13 | 'Sec-Fetch-Dest': 'iframe', 14 | 'Sec-Fetch-Mode': 'navigate', 15 | 'Sec-Fetch-Site': 'cross-site', 16 | 'Sec-Fetch-User': '?1', 17 | 'Sec-Gpc': '1', 18 | 'Sec-Ch-Ua-Mobile': '?1', 19 | 'Upgrade-Insecure-Requests': '1', 20 | 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1', 21 | } 22 | 23 | MSG_CURRENT_BALANCE = "Текущий баланс: {balance}" 24 | MSG_CURRENT_FRIENDS = "Рефералов: {total}" 25 | MSG_LOGIN_ERROR = "Ошибка при логине: {e}" 26 | MSG_TASK_COMPLETE = "Задание {slug}. +{reward} монет" 27 | MSG_TASK_ERROR = "Ошибка задания {slug}" 28 | -------------------------------------------------------------------------------- /bots/hamster_kombat/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TotalAwesome/BotFarmFactory/a014a70f66abbe1a46c9796847cd8813764978d1/bots/hamster_kombat/__init__.py -------------------------------------------------------------------------------- /bots/hamster_kombat/client.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from datetime import datetime 4 | from bots.base.base import BaseFarmer 5 | from base64 import b64decode 6 | from time import time, sleep 7 | from random import randrange, choice, random, uniform 8 | from threading import Thread 9 | from telethon.types import InputBotAppShortName 10 | from bots.hamster_kombat.promo import PromoGenerator 11 | from bots.hamster_kombat.strings import URL_BOOSTS_FOR_BUY, URL_BUY_BOOST, URL_BUY_UPGRADE, \ 12 | URL_SYNC, URL_TAP, URL_UPGRADES_FOR_BUY, HEADERS, BOOST_ENERGY, URL_CHECK_TASK, \ 13 | URL_CLAIM_DAILY_COMBO, MSG_BUY_UPGRADE, MSG_COMBO_EARNED, MSG_TAP, MSG_CLAIMED_COMBO_CARDS, \ 14 | MSG_SYNC, URL_CONFIG, URL_CLAIM_DAILY_CIPHER, MSG_CIPHER, URL_INIT, URL_AUTH, URL_SELECT_EXCHANGE, \ 15 | URL_LIST_TASKS, MSG_TASK_COMPLETED, MSG_TASK_NOT_COMPLETED, URL_GET_SKINS, URL_BUY_SKIN, \ 16 | PROMO_TOKENS, MSG_BUY_SKIN, MSG_PROMO_COMPLETED, \ 17 | URL_APPLY_PROMO, URL_GET_PROMOS, \ 18 | MSG_PROMO_UPDATE_ERROR, MSG_PROMO_OK, MSG_PROMO_ERROR, MSG_TRY_PROMO, MSG_PROMO_STATUS 19 | from bots.hamster_kombat.config import FEATURES 20 | from bots.hamster_kombat.utils import sorted_by_payback, sorted_by_price, sorted_by_profit, sorted_by_profitness, \ 21 | get_keys_count_per_game 22 | 23 | 24 | def generate_promo_keys(dict_with_keys, **kwargs): 25 | client = PromoGenerator(**kwargs) 26 | while True: 27 | new_key = client.get_promo() 28 | actual = dict_with_keys['actual'] 29 | activated = dict_with_keys['activated'] 30 | actual[client.promo_id] = actual.get(client.promo_id, []) 31 | activated[client.promo_id] = activated.get(client.promo_id, []) 32 | if not new_key in actual[client.promo_id] \ 33 | and not new_key in activated[client.promo_id]: 34 | actual[client.promo_id].append(new_key) 35 | sleep(5) 36 | 37 | 38 | class BotFarmer(BaseFarmer): 39 | 40 | name = 'hamster_kombat_bot' 41 | app_extra = 'kentId102796269' 42 | state = None 43 | boosts = None 44 | upgrades = None 45 | task_checked_at = None 46 | config_version = None 47 | promo_status = {} 48 | promo_threads = {} 49 | promo_keys = {'actual': {}, 50 | 'activated': {}} 51 | skins_info = [] 52 | my_skins_ids = [] 53 | 54 | @property 55 | def exchage_id(self): 56 | return self.state.get('exchangeId') 57 | 58 | @property 59 | def initialization_data(self): 60 | return dict(peer=self.name, 61 | app=InputBotAppShortName(self.initiator.get_input_entity(self.name), "start"), 62 | start_param=self.app_extra) 63 | 64 | def set_headers(self): 65 | self.headers = HEADERS.copy() 66 | self.start_promo_collector() 67 | 68 | def authenticate(self): 69 | init_data = self.initiator.get_auth_data(**self.initialization_data) 70 | result = self.post(URL_AUTH, json={"initDataRaw": init_data["authData"]}) 71 | if result.status_code == 200: 72 | if token := result.json().get('authToken'): 73 | self.headers['Authorization'] = f"Bearer {token}" 74 | self.set_exchange() 75 | return 76 | self.is_alive = False 77 | raise KeyError 78 | 79 | @property 80 | def promo_completed(self): 81 | return all([game['keys_per_day'] == game['keys_today'] 82 | for game in self.promo_status.values()]) 83 | 84 | def start_promo_collector(self): 85 | for promo_id, app_token in PROMO_TOKENS.items(): 86 | if not promo_id in BotFarmer.promo_threads: 87 | kwargs = dict(promo_id=promo_id, 88 | app_token=app_token, 89 | proxies=self.proxies, 90 | dict_with_keys=BotFarmer.promo_keys) 91 | thread = Thread(target=generate_promo_keys, kwargs=kwargs) 92 | BotFarmer.promo_threads[promo_id] = thread 93 | thread.start() 94 | 95 | def set_exchange(self): 96 | self.sync() 97 | if not self.exchage_id: 98 | eid = choice(('binance', 'okx', 'bybit', 'gate_io', 'bingx')) 99 | self.post(URL_SELECT_EXCHANGE, json={'exchangeId': eid}) 100 | 101 | def set_start_time(self): 102 | """ 103 | Берём минимальное из значений: 104 | - рандомного значения между минимальным и максимальным периодом до следующего захода 105 | - (если включены тапы) периода накопления энергии 106 | - (если включены промокоды и на сегодня введены не все) случайное значение от 10 до 15 минут 107 | """ 108 | sleep_seconds = [] 109 | minimum_farm_sleep = FEATURES.get("minimum_farm_sleep", 2 * 60 * 60) 110 | maximum_farm_sleep = FEATURES.get("maximum_farm_sleep", 3 * 60 * 60) 111 | bot_farm_sleep = uniform(minimum_farm_sleep, maximum_farm_sleep) 112 | sleep_seconds.append(bot_farm_sleep) 113 | if FEATURES.get('taps', True): 114 | tap_sleep_seconds = int(self.state['maxTaps'] / self.state['tapsRecoverPerSec']) 115 | sleep_seconds.append(tap_sleep_seconds) 116 | if FEATURES.get('apply_promo', True) and not self.promo_completed: 117 | promo_next_step = choice(range(10 * 60, 15 * 60)) 118 | sleep_seconds.append(promo_next_step) 119 | self.start_time = time() + min(sleep_seconds) 120 | 121 | def get_cipher_data(self): 122 | result = self.post(URL_CONFIG).json() 123 | return result['dailyCipher'] 124 | 125 | def claim_daily_cipher(self): 126 | """ Разгадываем морзянку """ 127 | cipher_data = self.get_cipher_data() 128 | if not cipher_data['isClaimed']: 129 | raw_cipher = cipher_data['cipher'][:3] + cipher_data['cipher'][4:] 130 | cipher = b64decode(raw_cipher).decode() 131 | self.log(MSG_CIPHER.format(cipher=cipher)) 132 | self.post(URL_CLAIM_DAILY_CIPHER, json={"cipher": cipher}) 133 | 134 | def get_skins_info(self): 135 | """ Получаем данные о скинах в игре """ 136 | response = self.get(f"{URL_CONFIG}/{self.config_version}") 137 | if response.status_code == 200: 138 | result = response.json() 139 | self.skins_info = result.get('config', {}).get('skins') 140 | 141 | def get_skins_state(self): 142 | """ Получаем данные о купленных скинах """ 143 | my_skins = self.state.get('skin', {}).get('available') 144 | self.my_skins_ids = [item['skinId'] for item in my_skins] 145 | 146 | def buy_skins(self): 147 | self.get_skins_info() 148 | self.get_skins_state() 149 | max_skin_price = FEATURES.get('max_skin_price', 0) 150 | for skin in self.skins_info: 151 | skin_price = skin.get('price') 152 | skin_id = skin.get('id') 153 | if ( 154 | skin_price <= self.balance 155 | and skin_price <= max_skin_price 156 | and skin_id not in self.my_skins_ids 157 | and (not skin.get('expiresAt') or datetime.utcnow() < datetime.fromisoformat(skin['expiresAt'][:-1])) 158 | ): 159 | response = self.buy_skin(skin_id) 160 | result = response.json() 161 | if response.status_code == 200: 162 | self.log(MSG_BUY_SKIN.format(skin_name=skin_id)) 163 | self.sync() 164 | sleep(2 + random()*5) 165 | else: 166 | break 167 | 168 | def buy_skin(self, skin_name): 169 | data = {"skinId": skin_name, "timestamp": int(time())} 170 | return self.post(URL_BUY_SKIN, json=data) 171 | 172 | def sync(self): 173 | self.log(MSG_SYNC) 174 | try: 175 | response = self.post(url=URL_SYNC) 176 | self.state = response.json()["clickerUser"] 177 | self.config_version = response.headers.get('config-version') 178 | except Exception as e: 179 | pass 180 | 181 | def daily_reward(self): 182 | """ Получение ежедневной награды """ 183 | data = {"taskId":"streak_days"} 184 | if not self.task_checked_at or time() - self.task_checked_at >= 60 * 60: 185 | self.post(URL_CHECK_TASK, json=data) 186 | self.task_checked_at = time() 187 | 188 | def tap(self): 189 | taps_count = self.available_taps or self.recover_per_sec 190 | data = {"count": taps_count, 191 | "availableTaps": self.available_taps - taps_count, 192 | "timestamp": int(time())} 193 | self.post(URL_TAP, json=data).json() 194 | self.log(MSG_TAP.format(taps_count=taps_count)) 195 | 196 | def boost(self, boost_name=BOOST_ENERGY): 197 | data = {"boostId": boost_name, "timestamp": int(time())} 198 | self.post(URL_BUY_BOOST, json=data) 199 | 200 | def upgrade(self, upgrade_name): 201 | data = {"upgradeId": upgrade_name, "timestamp": int(time())} 202 | return self.post(URL_BUY_UPGRADE, json=data) 203 | 204 | def upgrdades_list(self): 205 | self.upgrades = self.post(URL_UPGRADES_FOR_BUY).json() 206 | 207 | def boosts_list(self): 208 | self.boosts = self.post(URL_BOOSTS_FOR_BUY).json() 209 | 210 | @property 211 | def balance(self): 212 | if self.state: 213 | return self.state["balanceCoins"] 214 | 215 | @property 216 | def level(self): 217 | if self.state: 218 | return self.state["level"] 219 | 220 | @property 221 | def available_taps(self): 222 | if self.state: 223 | return self.state["availableTaps"] 224 | 225 | @property 226 | def recover_per_sec(self): 227 | if self.state: 228 | return self.state["tapsRecoverPerSec"] 229 | 230 | @property 231 | def is_taps_boost_available(self): 232 | self.boosts_list() 233 | if not self.boosts: 234 | return 235 | for boost in self.boosts["boostsForBuy"]: 236 | if ( 237 | boost["id"] == BOOST_ENERGY 238 | and boost["cooldownSeconds"] == 0 239 | and boost["level"] <= boost["maxLevel"] 240 | ): 241 | return True 242 | 243 | 244 | def get_sorted_upgrades(self, method): 245 | """ 246 | 1. Фильтруем карточки 247 | - доступные для покупки 248 | - не просроченные 249 | - с пассивным доходом 250 | - без ожидания перезарядки 251 | 2. Сортируем по профитности на каждую потраченную монету 252 | """ 253 | methods = dict(payback=sorted_by_payback, 254 | price=sorted_by_price, 255 | profit=sorted_by_profit, 256 | profitness=sorted_by_profitness) 257 | prepared = [] 258 | for upgrade in self.upgrades.get("upgradesForBuy"): 259 | if ( 260 | upgrade["isAvailable"] 261 | and not upgrade["isExpired"] 262 | and upgrade["profitPerHourDelta"] > 0 263 | and not upgrade.get("cooldownSeconds") 264 | and (not FEATURES['max_upgrade_payback'] or \ 265 | upgrade["price"] / upgrade["profitPerHourDelta"] <= FEATURES['max_upgrade_payback']) 266 | ): 267 | item = upgrade.copy() 268 | if 'condition' in item : 269 | item.pop('condition') 270 | prepared.append(item) 271 | if prepared: 272 | sorted_items = [i for i in methods[method](prepared)] # if i['price'] <= self.balance] 273 | return sorted_items 274 | return [] 275 | 276 | def buy_upgrades(self, method): 277 | """ Покупаем лучшие апгрейды на всю котлету """ 278 | while True: 279 | self.upgrdades_list() 280 | if sorted_upgrades := self.get_sorted_upgrades(method): 281 | upgrade = sorted_upgrades[0] 282 | if upgrade['price'] <= self.balance: 283 | result = self.upgrade(upgrade['id']) 284 | if result.status_code == 200: 285 | self.state = result.json()["clickerUser"] 286 | self.log(MSG_BUY_UPGRADE.format(**upgrade)) 287 | minimum_upgrade_delay = FEATURES.get("minimum_upgrade_delay", 5) 288 | maximum_upgrade_delay = FEATURES.get("maximum_upgrade_delay", 10) 289 | sleep(uniform(minimum_upgrade_delay, maximum_upgrade_delay) + random()) 290 | else: 291 | break 292 | else: 293 | break 294 | 295 | def claim_combo_reward(self): 296 | """ Если вдруг насобирал комбо - нужно получить награду """ 297 | combo = self.upgrades.get('dailyCombo', {}) 298 | upgrades = combo.get('upgradeIds', []) 299 | combo_cards = " ".join(upgrades) 300 | self.log(MSG_CLAIMED_COMBO_CARDS.format(cards=combo_cards)) 301 | if combo and len(upgrades) == 3: 302 | if combo.get('isClaimed') is False: 303 | result = self.post(URL_CLAIM_DAILY_COMBO) 304 | if result.status_code == 200: 305 | self.state = result.json()["clickerUser"] 306 | self.log(MSG_COMBO_EARNED.format(coins=combo['bonusCoins'])) 307 | 308 | def update_tasks(self): 309 | response = self.post(URL_LIST_TASKS) 310 | if response.status_code == 200: 311 | result = response.json() 312 | self.tasks = list(filter(lambda d: d['isCompleted'] != True, result["tasks"])) 313 | 314 | def make_tasks(self): 315 | self.update_tasks() 316 | for task in self.tasks: 317 | task_id = task['id'] 318 | reward = task['rewardCoins'] 319 | is_completed = task['isCompleted'] 320 | 321 | if not task_id.startswith('hamster_youtube'): 322 | continue 323 | 324 | if reward > 0: 325 | sleep(random() + choice(range(5, 10))) 326 | data = {'taskId': task_id} 327 | response = self.post(URL_CHECK_TASK, json=data) 328 | if response.status_code == 200: 329 | result = response.json() 330 | result = result["task"] 331 | is_completed = result.get('isCompleted') 332 | if is_completed: 333 | self.log(MSG_TASK_COMPLETED.format(reward=reward)) 334 | else: 335 | self.log(MSG_TASK_NOT_COMPLETED) 336 | 337 | def update_promos(self): 338 | response = self.post(URL_GET_PROMOS) 339 | if response.status_code == 200: 340 | result = response.json() 341 | self.promo_status = {} 342 | states = result.get('states', []) 343 | activated_keys = get_keys_count_per_game(states) 344 | for game in result.get('promos', []): 345 | self.promo_status[game['promoId']] = { 346 | "keys_per_day": game['keysPerDay'], 347 | "game_name": game['title']['en'], 348 | "keys_today": activated_keys.get(game['promoId'], 0), 349 | } 350 | else: 351 | self.log(MSG_PROMO_UPDATE_ERROR) 352 | self.promo_status = None 353 | 354 | def apply_promo(self): 355 | self.update_promos() 356 | for promo_id, promo_state in self.promo_status.items(): 357 | if promo_state['keys_per_day'] == (keys_today := promo_state['keys_today']): 358 | continue 359 | promo_keys = BotFarmer.promo_keys 360 | actual = promo_keys['actual'][promo_id] = promo_keys['actual'].get(promo_id, []) 361 | activated = promo_keys['activated'][promo_id] = promo_keys['activated'].get(promo_id, []) 362 | if actual: 363 | promo_code = actual.pop(0) 364 | data = {"promoCode": promo_code} 365 | self.log(MSG_TRY_PROMO.format(code=promo_code)) 366 | response = self.post(URL_APPLY_PROMO, json=data) 367 | if response.status_code == 200: 368 | result = response.json() 369 | self.promo_status[promo_id]['keys_today'] = result.get('promoState', {}).get('receiveKeysToday', keys_today) 370 | self.log(MSG_PROMO_OK) 371 | else: 372 | self.log(MSG_PROMO_ERROR) 373 | if activated: 374 | activated.pop(0) 375 | activated.append(promo_code) 376 | 377 | @property 378 | def stats(self): 379 | return { 380 | "уровень" : self.level, 381 | "энергия" : self.available_taps, 382 | 'баланс' : round(self.balance, 0), 383 | "доход в час" : round(self.state['earnPassivePerHour'], 0) 384 | } 385 | 386 | @property 387 | def log_prefix(self): 388 | return f"[{self.name}]\t " 389 | 390 | def farm(self): 391 | self.sync() 392 | self.claim_daily_cipher() 393 | if FEATURES.get('taps', True): 394 | self.tap() 395 | self.daily_reward() 396 | self.make_tasks() 397 | if FEATURES.get('buy_upgrades', True): 398 | self.buy_upgrades(FEATURES.get('buy_decision_method', 'payback')) 399 | self.claim_combo_reward() 400 | if FEATURES.get('buy_skins', True): 401 | self.buy_skins() 402 | if FEATURES.get('apply_promo', True): 403 | self.apply_promo() 404 | if self.is_taps_boost_available: 405 | self.boost(BOOST_ENERGY) 406 | self.log(" ".join(f"{k}: {v} |" for k, v in self.stats.items())) -------------------------------------------------------------------------------- /bots/hamster_kombat/config.py: -------------------------------------------------------------------------------- 1 | """ 2 | FEATURES: 3 | 1. buy_upgrades -> включение/отключение покупки карточек 4 | 2. buy_decision_method -> метод покупки карточек ( 5 | - price -> покупать самую дешевую 6 | - payback -> покупать ту, что быстрей всего окупится 7 | - profit -> покупать самую прибыльну 8 | - profitness -> покупать самую профитную (сколько добыча на каждый потраченный хома-рубль) 9 | ) 10 | 3. taps -> включение/отключение тапов 11 | 4. max_upgrade_payback - максимальная окупаемость апргейда в часах, например 40*100. По умолчанию - не ограничена. 12 | 5. buy_skins - покупать скины 13 | 6. apply_promo - получать и применять промокоды для игр 14 | 7. блок, отвечающий за таймауты 15 | 16 | """ 17 | 18 | 19 | FEATURES = { 20 | "buy_upgrades": True, 21 | "buy_decision_method": "payback", 22 | "taps": True, 23 | "max_upgrade_payback": None, 24 | "buy_skins": False, 25 | "max_skin_price": 10_000_000, 26 | "apply_promo": True, 27 | "minimum_farm_sleep": 2 * 60 * 60, # (2 часа) минимальная задержка до следующего захода 28 | "maximum_farm_sleep": 3 * 60 * 60, # (6 часов) максимальная задержка до следующего захода 29 | "minimum_upgrade_delay": 5, # (5 секунд) минимальная задержка между апгрейдами 30 | "maximum_upgrade_delay": 10, # (10 секунд) максимальная задержка между апгрейдами 31 | } 32 | 33 | 34 | try: 35 | from bots.hamster_kombat.config_local import * 36 | except ImportError: 37 | pass -------------------------------------------------------------------------------- /bots/hamster_kombat/promo.py: -------------------------------------------------------------------------------- 1 | """ 2 | (c) TotalAwesome 3 | """ 4 | 5 | import uuid 6 | import time 7 | import string 8 | from random import randint, choices, choice 9 | from requests import Session 10 | 11 | from bots.base.strings import USER_AGENTS 12 | from bots.hamster_kombat.strings import ( 13 | GET_PROMO_HEADERS, 14 | URL_REGISTER_EVENT, URL_LOGIN, URL_CREATE_CODE 15 | ) 16 | 17 | def generate_random_client_id(): 18 | current_time = int(time.time() * 1000) 19 | random_part = randint(100, 999) 20 | random_first = int(str(current_time)[:10] + str(random_part)) 21 | random_seconds = ''.join(choices(string.digits, k=19)) 22 | return f"{random_first}-{random_seconds}" 23 | 24 | 25 | def get_event_data(game_id): 26 | return {"promoId": game_id, 27 | "eventId": f"{uuid.uuid1()}", 28 | "eventOrigin": "undefined"} 29 | 30 | def retry(func): 31 | def wrapper(*args, **kwargs): 32 | while True: 33 | try: 34 | result = func(*args, **kwargs) 35 | if result.status_code == 200: 36 | return result 37 | elif result.status_code == 429: 38 | time.sleep(30) 39 | else: 40 | time.sleep(1) 41 | except Exception as e: 42 | time.sleep(5) 43 | return wrapper 44 | 45 | 46 | 47 | class PromoGenerator(Session): 48 | 49 | 50 | def __init__(self, app_token, promo_id, proxies) -> None: 51 | self.request = retry(self.request) 52 | super().__init__() 53 | self.headers = GET_PROMO_HEADERS 54 | self.app_token = app_token 55 | self.promo_id = promo_id 56 | self.proxies = proxies 57 | self.headers = {} 58 | self.headers['User-Agent'] = choice(USER_AGENTS) 59 | self.authenticate() 60 | 61 | def authenticate(self): 62 | payload = {"appToken": self.app_token, 63 | "clientId": generate_random_client_id(), 64 | "clientOrigin": "deviceid"} 65 | response = self.post(URL_LOGIN, json=payload, proxies=self.proxies) 66 | if response.status_code == 200: 67 | token = response.json()['clientToken'] 68 | self.headers['Authorization'] = 'Bearer ' + response.json()['clientToken'] 69 | return 70 | raise Exception('Can\'t log in') 71 | 72 | def get_promo(self): 73 | while True: 74 | self.post(URL_REGISTER_EVENT, json=get_event_data(game_id=self.promo_id), proxies=self.proxies) 75 | data = {"promoId": self.promo_id} 76 | response = self.post(URL_CREATE_CODE, json=data, proxies=self.proxies) 77 | if response.status_code == 200 and (promo := response.json().get('promoCode', '')): 78 | return promo 79 | time.sleep(1) 80 | 81 | 82 | if __name__ == '__main__': 83 | wizard = PromoGenerator() 84 | print(wizard.get_promo()) 85 | -------------------------------------------------------------------------------- /bots/hamster_kombat/strings.py: -------------------------------------------------------------------------------- 1 | # взаимодействие с API игры 2 | URL_CLAIM_DAILY_CIPHER = "https://api.hamsterkombatgame.io/clicker/claim-daily-cipher" 3 | URL_CLAIM_DAILY_COMBO = "https://api.hamsterkombatgame.io/clicker/claim-daily-combo" 4 | URL_UPGRADES_FOR_BUY = "https://api.hamsterkombatgame.io/clicker/upgrades-for-buy" 5 | URL_SELECT_EXCHANGE ="https://api.hamsterkombatgame.io/clicker/select-exchange" 6 | URL_BOOSTS_FOR_BUY = "https://api.hamsterkombatgame.io/clicker/boosts-for-buy" 7 | URL_AUTH = "https://api.hamsterkombatgame.io/auth/auth-by-telegram-webapp" 8 | URL_BUY_UPGRADE = "https://api.hamsterkombatgame.io/clicker/buy-upgrade" 9 | URL_LIST_TASKS = "https://api.hamsterkombatgame.io/clicker/list-tasks" 10 | URL_CHECK_TASK = "https://api.hamsterkombatgame.io/clicker/check-task" 11 | URL_BUY_BOOST = "https://api.hamsterkombatgame.io/clicker/buy-boost" 12 | URL_CONFIG = "https://api.hamsterkombatgame.io/clicker/config" 13 | URL_SYNC = "https://api.hamsterkombatgame.io/clicker/sync" 14 | URL_TAP = "https://api.hamsterkombatgame.io/clicker/tap" 15 | URL_INIT = "https://api.hamsterkombatgame.io/clicker" 16 | URL_GET_SKINS = "https://api.hamsterkombatgame.io/clicker/get-skin" 17 | URL_BUY_SKIN = "https://api.hamsterkombatgame.io/clicker/buy-skin" #POST\ 18 | URL_GET_PROMOS = "https://api.hamsterkombatgame.io/clicker/get-promos" 19 | URL_APPLY_PROMO = "https://api.hamsterkombatgame.io/clicker/apply-promo" 20 | 21 | # взаимодействие с генератором промокодов 22 | URL_REGISTER_EVENT = "https://api.gamepromo.io/promo/register-event" 23 | URL_LOGIN = "https://api.gamepromo.io/promo/login-client" 24 | URL_CREATE_CODE = "https://api.gamepromo.io/promo/create-code" 25 | 26 | # шаблоны сообщений в лог 27 | MSG_BUY_UPGRADE = "Прокачал: {name} : ур.{level} за {price} даст +{profitPerHourDelta}/час" 28 | MSG_SESSION_ERROR = "Ошибка во время выполнения запроса: {error}" 29 | MSG_COMBO_EARNED = "Получено вознаграждение за комбо: {coins}" 30 | MSG_BAD_RESPONSE = "Плохой ответ от сервера: {status} {text}" 31 | MSG_CLAIMED_COMBO_CARDS = "Уже получены комбо карты: {cards}" 32 | MSG_CRYPTED_CIPHER = "Шифрованный шифр: {cipher}" 33 | MSG_TAP = "Тапнул на {taps_count} монеток" 34 | MSG_CIPHER = "Новый шифр: {cipher}" 35 | MSG_SYNC = "Обновление данных" 36 | MSG_TASK_COMPLETED = "Задание выполнено. Награда: {reward}" 37 | MSG_TASK_NOT_COMPLETED = "Задание не выполнено" 38 | MSG_BUY_SKIN = "Скин {skin_name} куплен" 39 | 40 | 41 | MSG_PROMO_UPDATE_ERROR = "Ошибка обновления статуса промкодов" 42 | MSG_PROMO_STATUS = "Осталось ввести промокодов: {keys_left_status}" 43 | MSG_PROMO_COMPLETED = "Все промокоды введены" 44 | MSG_PROMO_OK = "Промокод применен успешно" 45 | MSG_PROMO_ERROR = "Промокод не применен" 46 | MSG_TRY_PROMO = "Попытка применения промокода: {code}" 47 | 48 | 49 | BOOST_ENERGY = "BoostFullAvailableTaps" 50 | 51 | HEADERS = { 52 | "Connection": "keep-alive", 53 | "sec-ch-ua": '"Chromium";v="122", "Not(A:Brand";v="24", "Android WebView";v="122"', 54 | "sec-ch-ua-mobile": '?1', 55 | "user-agent": "Mozilla/5.0 (Linux; Android 11; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.64 Mobile Safari/537.36", 56 | "sec-ch-ua-platform": '"Android"', 57 | "Accept": "*/*", 58 | "Origin": "https://hamsterkombatgame.io", 59 | "X-Requested-With": "org.telegram.messenger", 60 | "Sec-Fetch-Site": "same-site", 61 | "Sec-Fetch-Mode": "cors", 62 | "Sec-Fetch-Dest": "empty", 63 | "Referer": "https://hamsterkombatgame.io/", 64 | "Accept-Encoding": "gzip, deflate, br", 65 | } 66 | 67 | GET_PROMO_HEADERS = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", 68 | "Content-Type": "application/json; charset=utf-8", 69 | "Host": "api.gamepromo.io"} 70 | 71 | PROMO_TOKENS = { 72 | # promo_id : app_token 73 | '43e35910-c168-4634-ad4f-52fd764a843f': 'd28721be-fd2d-4b45-869e-9f253b554e50', # BIKE 74 | 'fe693b26-b342-4159-8808-15e3ff7f8767': '74ee0b5b-775e-4bee-974f-63e7f4d5bacb', # CLONE 75 | 'b4170868-cef0-424f-8eb9-be0622e8e8e3': 'd1690a07-3780-4068-810f-9b5bbf2931b2', # CUBE 76 | 'c4480ac7-e178-4973-8061-9ed5b2e17954': '82647f43-3f87-402d-88dd-09a90025313f', # TRAIN 77 | 'dc128d28-c45b-411c-98ff-ac7726fbaea4': '8d1cc2ad-e097-4b86-90ef-7a27e19fb833', # MERGE 78 | '61308365-9d16-4040-8bb0-2f4a4c69074c': '61308365-9d16-4040-8bb0-2f4a4c69074c', # TWERK 79 | '2aaf5aee-2cbc-47ec-8a3f-0962cc14bc71': '2aaf5aee-2cbc-47ec-8a3f-0962cc14bc71', # POLY 80 | } -------------------------------------------------------------------------------- /bots/hamster_kombat/utils.py: -------------------------------------------------------------------------------- 1 | def sorted_by_profit(prepared): 2 | return sorted(prepared, key=lambda x: x["profitPerHourDelta"], reverse=True) 3 | 4 | 5 | def sorted_by_profitness(prepared): 6 | return sorted( 7 | prepared, key=lambda x: x["profitPerHourDelta"] / x["price"], reverse=True 8 | ) 9 | 10 | 11 | def sorted_by_price(prepared): 12 | return sorted(prepared, key=lambda x: x["price"], reverse=False) 13 | 14 | 15 | def sorted_by_payback(prepared): 16 | return sorted( 17 | prepared, key=lambda x: x["price"] / x["profitPerHourDelta"], reverse=False 18 | ) 19 | 20 | def get_keys_count_per_game(states): 21 | result = {} 22 | for state in states: 23 | result[state['promoId']] = state["receiveKeysToday"] 24 | return result 25 | -------------------------------------------------------------------------------- /bots/hexn/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /bots/hexn/client.py: -------------------------------------------------------------------------------- 1 | """ 2 | Author: Eyn 3 | Date: 18-07-2024 4 | 5 | """ 6 | from time import sleep, time 7 | 8 | from bots.base.base import BaseFarmer 9 | from bots.hexn.strings import HEADERS, URL_INIT, URL_LOGIN, MSG_FARMING_ALREADY_STARTED, MSG_FARMING_ERROR, URL_CLAIM, \ 10 | MSG_CLAIMED, \ 11 | MSG_CURRENT_BALANCE, URL_START_FARMING, MSG_FARMING_STARTED, MSG_QUEST_COMPLETED, MSG_QUEST_ERROR, \ 12 | MSG_QUEST_STARTING_ERROR, URL_QUEST_START, URL_QUEST_CLAIM 13 | 14 | DEFAULT_EST_TIME = 60 * 10 15 | 16 | 17 | class BotFarmer(BaseFarmer): 18 | name = "hexn_bot" 19 | codes_to_refresh = (401,) 20 | refreshable_token = True 21 | user_data = None 22 | auth_data = None 23 | balance = None 24 | end_time = None 25 | farming_data = None 26 | referral = 'tgWebAppStartParam=63b093b0-fcb8-41b5-8f50-bc61983ef4e3' 27 | initialization_data = dict(peer=name, bot=name, url=URL_INIT, start_param=referral) 28 | 29 | def set_headers(self, *args, **kwargs): 30 | self.headers = HEADERS.copy() 31 | 32 | def authenticate(self, *args, **kwargs): 33 | init_data = self.initiator.get_auth_data(**self.initialization_data) 34 | 35 | self.auth_data = init_data['authData'] 36 | data = { 37 | 'init_data': init_data['authData'] 38 | } 39 | try: 40 | result = self.post(URL_LOGIN, json=data) 41 | 42 | if result.status_code == 200: 43 | json_data = result.json() 44 | if json_data['status'] == 'OK': 45 | self.user_data = user_data = json_data['data'] 46 | self.balance = user_data.get('balance') 47 | self.is_alive = True 48 | except Exception as e: 49 | self.is_alive = False 50 | self.log(str(e), error=True) 51 | 52 | def set_start_time(self): 53 | if self.end_time: 54 | self.start_time = self.end_time 55 | else: 56 | est_time = DEFAULT_EST_TIME 57 | self.start_time = time() + est_time 58 | 59 | def check_farming_status(self): 60 | 61 | farming_status = self.user_data.get('farming', {}) 62 | 63 | if not farming_status: 64 | self.start_farming() 65 | 66 | if farming_status.get('end_at', 0) // 1000 > time(): 67 | self.log(MSG_FARMING_ALREADY_STARTED) 68 | self.end_time = farming_status.get('end_at', 0) // 1000 69 | 70 | return 71 | else: 72 | self.claim() 73 | 74 | def start_farming(self): 75 | 76 | data = { 77 | 'init_data': self.auth_data, 78 | } 79 | 80 | result = self.post(URL_START_FARMING, json=data) 81 | response_json = result.json() 82 | 83 | if response_json.get('status') == 'OK': 84 | self.log(MSG_FARMING_STARTED) 85 | 86 | self.get_state() 87 | 88 | farming_status = self.user_data.get('farming', {}) 89 | self.end_time = farming_status.get('end_at', 0) // 1000 90 | 91 | def claim(self): 92 | data = { 93 | 'init_data': self.auth_data, 94 | } 95 | 96 | result = self.post(URL_CLAIM, json=data) 97 | response_json = result.json() 98 | 99 | if response_json.get('status') == 'OK': 100 | self.log(MSG_CLAIMED) 101 | 102 | self.start_farming() 103 | else: 104 | self.log(MSG_FARMING_ERROR) 105 | 106 | def farm(self): 107 | self.show_balance() 108 | self.check_farming_status() 109 | self.quests() 110 | self.show_balance() 111 | 112 | def get_state(self): 113 | data = { 114 | 'init_data': self.auth_data 115 | } 116 | try: 117 | result = self.post(URL_LOGIN, json=data) 118 | 119 | if result.status_code == 200: 120 | json_data = result.json() 121 | if json_data['status'] == 'OK': 122 | self.user_data = user_data = json_data['data'] 123 | self.balance = user_data.get('balance') 124 | except Exception as e: 125 | self.log(str(e), error=True) 126 | 127 | def show_balance(self): 128 | self.get_state() 129 | self.log(MSG_CURRENT_BALANCE.format(balance=self.balance)) 130 | 131 | def quests(self): 132 | executed_quests = self.user_data.get('executed_quests', {}) 133 | 134 | for quest_id, quest in self.user_data['config']['quests'].items(): 135 | if str(quest_id) not in executed_quests: 136 | quest_name = quest.get('description', 'Unnamed Quest') 137 | quest_points = quest.get('points_amount', 'Unknown amount') 138 | 139 | data = { 140 | 'init_data': self.auth_data, 141 | 'quest_id': int(quest_id) 142 | } 143 | try: 144 | self.post(URL_QUEST_START, json=data) 145 | except Exception as e: 146 | self.log(MSG_QUEST_STARTING_ERROR.format(quest_name=quest_name)) 147 | 148 | continue 149 | 150 | sleep(5) 151 | 152 | result = self.post(URL_QUEST_CLAIM, json=data) 153 | response_json = result.json() 154 | 155 | if response_json.get('status') == 'OK': 156 | 157 | self.log(MSG_QUEST_COMPLETED.format(quest_name=quest_name, quest_points=quest_points)) 158 | else: 159 | self.log(MSG_QUEST_ERROR.format(quest_name=quest_name)) 160 | -------------------------------------------------------------------------------- /bots/hexn/strings.py: -------------------------------------------------------------------------------- 1 | URL_INIT = 'https://tgapp.hexn.cc?tgWebAppStartParam=63b093b0-fcb8-41b5-8f50-bc61983ef4e3' # ?tgWebAppStartParam=63b093b0-fcb8-41b5-8f50-bc61983ef4e3 2 | URL_LOGIN = 'https://clicker.hexn.cc/v1/state' 3 | URL_START_FARMING = 'https://clicker.hexn.cc/v1/farming/start' 4 | URL_CLAIM = 'https://clicker.hexn.cc/v1/farming/claim' 5 | URL_QUEST_START = 'https://clicker.hexn.cc/v1/executed-quest/start' 6 | URL_QUEST_CLAIM = 'https://clicker.hexn.cc/v1/executed-quest/claim' 7 | 8 | HEADERS = { 9 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0' 10 | } 11 | 12 | MSG_CURRENT_BALANCE = 'Баланс {balance}' 13 | MSG_FARMING_ALREADY_STARTED = "Фарминг уже запущен" 14 | MSG_FARMING_STARTED = "Фарминг успешно запущен" 15 | MSG_FARMING_ERROR = "Ошибка фарминга" 16 | MSG_UNKNOWN_RESPONSE = "Неизвестный ответ" 17 | MSG_CLAIMED = 'Собрал монеты' 18 | MSG_QUEST_COMPLETED = 'Квест {quest_name}. +{quest_points} монет' 19 | MSG_QUEST_ERROR = 'Ошибка квеста {quest_name}' 20 | MSG_QUEST_STARTING_ERROR = 'Ошибка начала квеста {quest_name}' 21 | -------------------------------------------------------------------------------- /bots/iceberg/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /bots/iceberg/client.py: -------------------------------------------------------------------------------- 1 | from random import random 2 | from time import time 3 | from bots.base.base import BaseFarmer 4 | from bots.base.utils import to_localtz_timestamp, api_response 5 | from bots.iceberg.strings import HEADERS, URL_BALANCE, URL_FARMING, URL_INIT, \ 6 | MSG_CLAIM, MSG_FARM, MSG_PROFILE, MSG_STATE, URL_CLAIM_FARM 7 | 8 | 9 | class BotFarmer(BaseFarmer): 10 | name = "icebergappbot" 11 | info = {} 12 | extra_code = "referral_102796269" 13 | initialization_data = dict(peer=name, bot=name, url=URL_INIT) 14 | payload_base = {} 15 | 16 | @property 17 | def claim_time(self): 18 | date_str = self.info.get("farming", {}).get("stop_time") 19 | return to_localtz_timestamp(date_str) if date_str else time() - 10 # При первом фарме, нет данных 20 | 21 | def set_headers(self, *args, **kwargs): 22 | self.headers = HEADERS.copy() 23 | self.get = api_response(super().get) 24 | self.post = api_response(super().post) 25 | self.delete = api_response(super().delete) 26 | 27 | def authenticate(self, *args, **kwargs): 28 | auth_data = self.initiator.get_auth_data(**self.initialization_data)["authData"] 29 | self.headers["x-telegram-auth"] = auth_data 30 | 31 | def update_profile(self): 32 | if response := self.get(URL_FARMING): 33 | self.info['farming'] = response 34 | if response := self.get(URL_BALANCE): 35 | self.info["balance"] = response 36 | self.log(MSG_PROFILE) 37 | 38 | def set_start_time(self): 39 | self.start_time = self.claim_time + random() * 10 40 | 41 | def claim(self): 42 | if self.claim_time <= time(): 43 | if response := self.delete(URL_CLAIM_FARM): 44 | self.log(MSG_CLAIM) 45 | 46 | def start_farm(self): 47 | self.update_profile() 48 | if self.claim_time <= time() and self.info.get("farming", {}).get("amount", 0) == 0: 49 | if response := self.post(URL_FARMING): 50 | self.info['farming'] = response 51 | self.log(MSG_FARM) 52 | 53 | def farm(self): 54 | self.start_farm() 55 | self.claim() 56 | self.log(MSG_STATE.format(balance=self.info["balance"]["amount"])) 57 | -------------------------------------------------------------------------------- /bots/iceberg/strings.py: -------------------------------------------------------------------------------- 1 | URL_INIT = "https://0xiceberg.com/webapp/" 2 | URL_BALANCE = "https://0xiceberg.com/api/v1/web-app/balance/" 3 | URL_FARMING = "https://0xiceberg.com/api/v1/web-app/farming/" # GET / POST 4 | URL_TASKS = "https://0xiceberg.com/api/v1/web-app/tasks/" 5 | URL_CLAIM_FARM = "https://0xiceberg.com/api/v1/web-app/farming/collect/" # DELETE 6 | 7 | MSG_PROFILE = "Обновил профиль" 8 | MSG_CLAIM = "Собрал нафармленное" 9 | MSG_FRIENDS_CLAIM = "Собрал нафармленное рефералами" 10 | MSG_FARM = "Начал фармить" 11 | MSG_STATE = "Баланс: {balance}" 12 | 13 | HEADERS = { 14 | 'authority': '0xiceberg.com' , 15 | 'accept': '*/*' , 16 | 'accept-language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7,cy;q=0.6' , 17 | 'cache-control': 'no-cache' , 18 | 'content-length': '0' , 19 | 'origin': 'https://0xiceberg.com' , 20 | 'pragma': 'no-cache' , 21 | 'referer': 'https://0xiceberg.com/webapp/' , 22 | 'sec-ch-ua': '"Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"' , 23 | 'sec-ch-ua-mobile': '?0' , 24 | 'sec-ch-ua-platform': '"Linux"' , 25 | 'sec-fetch-dest': 'empty' , 26 | 'sec-fetch-mode': 'cors' , 27 | 'sec-fetch-site': 'same-origin' , 28 | 'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36' , 29 | 'x-telegram-auth': '', 30 | } 31 | -------------------------------------------------------------------------------- /bots/onewin/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TotalAwesome/BotFarmFactory/a014a70f66abbe1a46c9796847cd8813764978d1/bots/onewin/__init__.py -------------------------------------------------------------------------------- /bots/onewin/client.py: -------------------------------------------------------------------------------- 1 | import json 2 | import re 3 | from time import time as current_time, sleep 4 | from random import choice, uniform, random 5 | from bots.base.base import BaseFarmer 6 | from telethon.types import InputBotAppShortName 7 | from bots.onewin.strings import ( 8 | HEADERS, BUILDING_INFO, 9 | URL_INIT, URL_ACCOUNT_BALANCE, URL_DAILY_REWARD_INFO, URL_MINING, 10 | URL_FRIENDS_INFO, URL_FRIEND_CLAIM, 11 | MSG_CURRENT_BALANCE, MSG_DAILY_REWARD, MSG_DAILY_REWARD_IS_COLLECTED, 12 | MSG_BUY_UPGRADE, MSG_BUY_BUILDING, MSG_ACCESS_TOKEN_ERROR, MSG_URL_ERROR, 13 | MSG_AUTHENTICATION_ERROR, MSG_ACCOUNT_INFO_ERROR, MSG_DAILY_REWARD_ERROR, 14 | MSG_INITIALIZATION_ERROR,MSG_FRIENDS_REWARD,MSG_FRIENDS_REWARD_ERROR 15 | ) 16 | from bots.onewin.config import ( 17 | FEATURES,UPGRADE_MAX_LEVEL 18 | ) 19 | 20 | 21 | def sorted_by_payback(prepared): 22 | return sorted(prepared, key=lambda x: x['cost'] / x['profit'], reverse=False) 23 | 24 | 25 | class BotFarmer(BaseFarmer): 26 | name = "token1win_bot" 27 | auth_data = None 28 | token = None 29 | extra_code = "refId6370423806" 30 | friends_coins = 0 31 | friends = 0 32 | 33 | @property 34 | def initialization_data(self): 35 | return dict(peer=self.name, 36 | app=InputBotAppShortName(self.initiator.get_input_entity(self.name), "start"), 37 | start_param=self.extra_code) 38 | 39 | def authenticate(self): 40 | if not self.auth_data: 41 | try: 42 | init_data = self.initiator.get_auth_data(**self.initialization_data) 43 | self.auth_data = init_data 44 | except Exception as e: 45 | self.log(MSG_INITIALIZATION_ERROR.format(error=e)) 46 | try: 47 | self.headers['x-user-id'] = str(self.auth_data['userId']) 48 | headers = self.headers.copy() 49 | response = self.post(URL_INIT, headers=headers, params=self.auth_data['authData']) 50 | if response.status_code == 200: 51 | result = response.json() 52 | if token := result.get("token"): 53 | self.headers["Authorization"] = f"Bearer {token}" 54 | else: 55 | self.error(MSG_ACCESS_TOKEN_ERROR) 56 | else: 57 | self.error(MSG_AUTHENTICATION_ERROR.format(status_code=response.status_code, text=response.text)) 58 | except Exception as e: 59 | self.log(MSG_URL_ERROR.format(error=e)) 60 | 61 | def set_headers(self): 62 | self.headers = HEADERS.copy() 63 | 64 | def get_info(self, show=False): 65 | response = self.get(url=URL_ACCOUNT_BALANCE, headers=self.headers) 66 | if response.status_code == 200: 67 | result = response.json() 68 | self.balance = result.get("coinsBalance", 0) 69 | if show: 70 | self.log(MSG_CURRENT_BALANCE.format(coins=self.balance)) 71 | else: 72 | self.error(MSG_ACCOUNT_INFO_ERROR.format(status_code=response.status_code,text=response.text)) 73 | 74 | def daily_reward_info(self): 75 | response = self.get(URL_DAILY_REWARD_INFO, headers=self.headers) 76 | if response.status_code == 200: 77 | result = response.json() 78 | self.daily_reward_is_collected = result["days"][0]["isCollected"] 79 | 80 | def get_daily_reward(self): 81 | self.daily_reward_info() 82 | if self.daily_reward_is_collected == None: 83 | return None 84 | elif self.daily_reward_is_collected == False: 85 | response = self.post(url=URL_DAILY_REWARD_INFO, headers=self.headers) 86 | if response.status_code == 200: 87 | result = response.json() 88 | self.daily_reward = result["days"][0]["money"] 89 | self.log(MSG_DAILY_REWARD.format(coins=self.daily_reward)) 90 | else: 91 | self.error(MSG_DAILY_REWARD_ERROR.format(status_code=response.status_code,text=response.text)) 92 | else: 93 | self.log(MSG_DAILY_REWARD_IS_COLLECTED) 94 | 95 | def friends_info(self): 96 | response = self.get(URL_FRIENDS_INFO, headers=self.headers) 97 | if response.status_code == 200: 98 | result = response.json() 99 | self.friends = result.get("total_friends", 0) 100 | self.friends_coins = result.get("total_coins", 0) 101 | 102 | def friends_claim(self): 103 | self.friends_info() 104 | if self.friends_coins > 0: 105 | response = self.post(url=URL_FRIEND_CLAIM, headers=self.headers) 106 | if response.status_code == 200: 107 | result = response.json() 108 | coins_collected = result.get("coinsCollected", 0) 109 | self.log(MSG_FRIENDS_REWARD.format(coins=coins_collected)) 110 | else: 111 | self.error(MSG_FRIENDS_REWARD_ERROR.format(status_code=response.status_code,text=response.text)) 112 | 113 | def upgrades_list(self): 114 | response = self.get(URL_MINING, headers=self.headers) 115 | if response.status_code == 200: 116 | self.upgrades = response.json() 117 | 118 | def get_sorted_upgrades(self, sort_method): 119 | """ 120 | 1. Фильтруем карточки 121 | - доступные для покупки 122 | - с пассивным доходом 123 | 2. Сортируем по профитности на каждую потраченную монету 124 | """ 125 | methods = dict(payback=sorted_by_payback) 126 | prepared = [] 127 | self.upgrades_list() 128 | for upgrade in self.upgrades: 129 | if ( 130 | upgrade["profit"] > 0 131 | and upgrade["level"] <= UPGRADE_MAX_LEVEL - 1 132 | and upgrade["cost"] <= FEATURES["max_upgrade_cost"] 133 | and upgrade["cost"] / upgrade["profit"] <= FEATURES["max_upgrade_payback"] 134 | ): 135 | upgrade["payback"] = round(upgrade["cost"] / upgrade["profit"],2) 136 | item = upgrade.copy() 137 | prepared.append(item) 138 | if prepared: 139 | sorted_items = [i for i in methods[sort_method](prepared)] 140 | return sorted_items 141 | return [] 142 | 143 | def buy_upgrades(self): 144 | """ Покупаем лучшие апгрейды на всю котлету """ 145 | if FEATURES["buy_upgrades"]: 146 | counter = 0 147 | num_purchases_per_cycle = FEATURES["num_purchases_per_cycle"] 148 | while True: 149 | if sorted_upgrades := self.get_sorted_upgrades(FEATURES["buy_decision_method"]): 150 | upgrade = sorted_upgrades[0] 151 | if upgrade["cost"]*2 <= self.balance \ 152 | and self.balance > FEATURES["min_cash_value_in_balance"] \ 153 | and num_purchases_per_cycle and counter < num_purchases_per_cycle: 154 | self.upgrade(upgrade['id']) 155 | sleep(2 + random() * 3) 156 | else: 157 | break 158 | else: 159 | break 160 | 161 | def upgrade(self, upgrade_id, new_building=False): 162 | data = {"id": upgrade_id} 163 | english_name = re.sub(r'\d+', '', upgrade_id).lower() 164 | russian_name = BUILDING_INFO.get(english_name)["rus_name"] 165 | if new_building == False: 166 | match = re.search(r'\d+', data['id']) 167 | if match: 168 | current_level = int(match.group()) 169 | upgrade_level = current_level + 1 170 | new_id = data['id'].replace(str(current_level), str(upgrade_level)) 171 | data['id'] = new_id 172 | response = self.post(URL_MINING, json=data) 173 | if response.status_code == 200: 174 | self.log(MSG_BUY_UPGRADE.format(name=russian_name, level=upgrade_level)) 175 | else: 176 | response = self.post(URL_MINING, json=data) 177 | if response.status_code == 200: 178 | self.log(MSG_BUY_BUILDING.format(name=russian_name)) 179 | self.get_info() 180 | 181 | def buy_new_buildings(self): 182 | my_buildings = {} 183 | for upgrade in self.upgrades: 184 | try: 185 | building_name = re.sub(r'\d+', '', upgrade["id"]).lower() 186 | building_level = upgrade["level"] 187 | my_buildings[building_name] = building_level 188 | except Exception as e: 189 | pass 190 | new_buildings = list(BUILDING_INFO.keys()) 191 | self.get_info() 192 | for item in new_buildings: 193 | if not my_buildings.get(item): 194 | requirements = BUILDING_INFO[item]["requirements"] 195 | if (requirements == None) or (requirements["level"]<=my_buildings.get(requirements["name"],0)): 196 | if BUILDING_INFO[item]["min_balance"] <= self.balance: 197 | self.upgrade(BUILDING_INFO[item]["purchase_id"], new_building=True) 198 | 199 | def set_start_time(self): 200 | self.start_time = current_time() + uniform(FEATURES["minimum_delay"],FEATURES["maximum_delay"]) 201 | 202 | def farm(self): 203 | self.authenticate() 204 | self.get_info(show=True) 205 | if FEATURES['get_daily_reward']: 206 | self.get_daily_reward() 207 | if FEATURES['friends_claim']: 208 | self.friends_claim() 209 | self.upgrades_list() 210 | if FEATURES['blind_upgrade']: 211 | self.buy_new_buildings() 212 | self.buy_upgrades() 213 | 214 | -------------------------------------------------------------------------------- /bots/onewin/config.py: -------------------------------------------------------------------------------- 1 | UPGRADE_MAX_LEVEL = 20 2 | 3 | try: 4 | from config_local import FEATURES 5 | except: 6 | 7 | FEATURES = { 8 | "minimum_delay": 3*60*60, # (3 часа) минимальная задержка до следующего захода 9 | "maximum_delay": 6*60*60, # (6 часов) максимальная задержка до следующего захода 10 | "get_daily_reward": True, # забирать ежедневную награду 11 | "buy_upgrades": True, # покупать апргейды 12 | "buy_decision_method": "payback", # логика выбора апгрейдов 13 | "num_purchases_per_cycle": 10, # количество покупок апгрейдов за циклв 14 | "max_upgrade_cost": 500_000, # максимальная стоимость апгрейда 15 | "max_upgrade_payback": 3600, # максимальная окупаемость апгрейда в часах 16 | "min_cash_value_in_balance": 10_000, # минимальный остаток после апгрейда 17 | "blind_upgrade": True, # попытка покупки 1 уровня нового здания, основываясь на хардкодных данных 18 | "friends_claim": True # забирать награду от рефов 19 | } 20 | 21 | 22 | ''' 23 | Если хочется установить свои параметры для модуля, последовательность действий: 24 | 1. Создайте файл config_local.py 25 | 2. Пример содержимого: 26 | 27 | FEATURES = [ 28 | "get_daily_reward": True, 29 | ] 30 | 31 | В результате, ваш конфиг не будет перезатираться при обновлении фабрики. 32 | 33 | ''' -------------------------------------------------------------------------------- /bots/onewin/strings.py: -------------------------------------------------------------------------------- 1 | URL_INIT = "https://crypto-clicker-backend-go-prod.100hp.app/game/start" 2 | URL_ACCOUNT_BALANCE = "https://crypto-clicker-backend-go-prod.100hp.app/user/balance" #GET 3 | URL_DAILY_REWARD_INFO = "https://crypto-clicker-backend-go-prod.100hp.app/tasks/everydayreward" #GET 4 | URL_TAP = "https://crypto-clicker-backend-go-prod.100hp.app/tap" #POST 5 | URL_MINING = "https://crypto-clicker-backend-go-prod.100hp.app/minings" #GET 6 | URL_MINING_UPGRADE = "https://crypto-clicker-backend-go-prod.100hp.app/minings" #POST Пример id: "coinflip15" 7 | URL_FRIENDS_INFO = "https://crypto-clicker-backend-go-prod.100hp.app/friends?offset=0&limit=5" 8 | URL_FRIEND_CLAIM = "https://crypto-clicker-backend-go-prod.100hp.app/friends/collect" #POST 9 | 10 | MSG_INITIALIZATION_ERROR = "Ошибка инициализации" 11 | MSG_ACCESS_TOKEN_ERROR = "Не удалось получить access token" 12 | MSG_AUTHENTICATION_ERROR = "Ошибка аутентификации. Код состояния: {status_code}, Ответ: {text}" 13 | MSG_URL_ERROR = "Ошибка при разборе URL для аутентификации: {error}" 14 | MSG_ACCOUNT_INFO_ERROR = "Не получена информация об аккаунте. Код состояния: {status_code}, Ответ: {text}" 15 | MSG_CURRENT_BALANCE = "Текущий баланс - {coins} монет" 16 | MSG_BUY_UPGRADE = "Прокачал: {name} : ур.{level}" 17 | MSG_DAILY_REWARD = "Забрал ежедневную награду - {coins} монет" 18 | MSG_DAILY_REWARD_ERROR = "Не получена ежедневная награда. Код состояния: {status_code}, Ответ: {text}" 19 | MSG_DAILY_REWARD_IS_COLLECTED = "Ежедневная награда уже получена" 20 | MSG_FRIENDS_REWARD = "Забрал награду от рефералов - {coins} монет" 21 | MSG_FRIENDS_REWARD_ERROR = "Не получена награда от рефералов. Код состояния: {status_code}, Ответ: {text}" 22 | MSG_BUY_BUILDING = "Здание {name} куплено" 23 | 24 | BUILDING_INFO = { 25 | "coinflip": {"purchase_id": "coinflip1", "rus_name": "Такси", 26 | "requirements": None, 27 | "min_balance": 2_000}, 28 | "mines": {"purchase_id": "Mines1", "rus_name": "Продуктовый магазин", 29 | "requirements": None, 30 | "min_balance": 2_000}, 31 | "bombucks": {"purchase_id":"Bombucks1", "rus_name": "Стриминг", 32 | "requirements": None, 33 | "min_balance": 2_000}, 34 | "tower": {"purchase_id":"Tower1", "rus_name": "Майнинг ферма", 35 | "requirements": None, 36 | "min_balance": 2_000}, 37 | "double":{"purchase_id":"Double1", "rus_name": "Барбершоп", 38 | "requirements": {"name":"mines", "level":8}, 39 | "min_balance": 10_000}, 40 | "royalmines":{"purchase_id":"RoyalMines1", "rus_name": "Автосалон", 41 | "requirements": {"name":"coinflip", "level":5}, 42 | "min_balance": 10_000}, 43 | "luckyloot":{"purchase_id":"LuckyLoot1", "rus_name": "Рекламное агентство", 44 | "requirements": {"name":"coinflip", "level":11}, 45 | "min_balance": 10_000}, 46 | "brawlpirates":{"purchase_id":"BrawlPirates1", "rus_name": "Компьютерный клуб", 47 | "requirements": {"name":"bombucks", "level":3}, 48 | "min_balance": 10_000}, 49 | "anubisplinko":{"purchase_id":"AnubisPlinko1", "rus_name": "Фитнес клуб", 50 | "requirements": {"name":"tower", "level":7}, 51 | "min_balance": 20_000}, 52 | "rocketx":{"purchase_id":"RocketX1", "rus_name": "Кинотеатр", 53 | "requirements": {"name":"anubisplinko", "level":10}, 54 | "min_balance": 20_000}, 55 | "speedncash":{"purchase_id":"SpeednCash1", "rus_name": "Торговый центр", 56 | "requirements": {"name":"rocketx", "level":9}, 57 | "min_balance": 20_000}, 58 | "rocketqueen":{"purchase_id":"RocketQueen1", "rus_name": "Отель", 59 | "requirements": {"name":"speedncash", "level":12}, 60 | "min_balance": 20_000}, 61 | "luckyjet":{"purchase_id":"LuckyJet1", "rus_name": "Маркетплейс", 62 | "requirements": {"name":"brawlpirates", "level":7}, 63 | "min_balance": 20_000}, 64 | "airjet":{"purchase_id":"AirJet1", "rus_name": "Каршеринг", 65 | "requirements": {"name":"anubisplinko", "level":7}, 66 | "min_balance": 20_000}, 67 | "fortunecrash":{"purchase_id":"FortuneCrash1", "rus_name": "Онлайн школа", 68 | "requirements": {"name":"luckyloot", "level":3}, 69 | "min_balance": 20_000} 70 | } 71 | 72 | 73 | HEADERS = { 74 | 'Content-Type': 'application/json', 75 | 'sec-ch-ua': '"Chromium";v="122", "Not(A:Brand";v="24", "Android WebView";v="122"', 76 | 'sec-ch-ua-mobile': '?1', 77 | 'sec-ch-ua-platform': '"Android"', 78 | 'origin': 'https://cryptocklicker-frontend-rnd-prod.100hp.app', 79 | 'x-requested-with': 'org.telegram.messenger', 80 | 'sec-fetch-site': 'same-site', 81 | 'sec-fetch-mode': 'cors', 82 | 'sec-fetch-dest': 'empty', 83 | 'referer': 'https://cryptocklicker-frontend-rnd-prod.100hp.app/', 84 | 'accept-language': 'ru,ru-RU;q=0.9,en-US;q=0.8,en;q=0.7' 85 | } 86 | 87 | -------------------------------------------------------------------------------- /bots/orbitonx/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TotalAwesome/BotFarmFactory/a014a70f66abbe1a46c9796847cd8813764978d1/bots/orbitonx/__init__.py -------------------------------------------------------------------------------- /bots/orbitonx/client.py: -------------------------------------------------------------------------------- 1 | import json 2 | from time import sleep 3 | from random import random 4 | from telethon.types import InputBotAppShortName 5 | from bots.base.base import BaseFarmer, time 6 | from bots.base.utils import api_response, to_localtz_timestamp 7 | from urllib.parse import unquote 8 | 9 | from bots.orbitonx.strings import URL_AUTH, URL_INIT, HEADERS, MSG_AUTH_ERROR, URL_INFO, URL_BALANCE, URL_QUESTS, \ 10 | URL_STAKING_CLAIM, URL_TAP, MSG_STAKING_CLAIMED, MSG_STAKING_STARTED, MSG_STAKING_TAP, URL_TASKS, \ 11 | MSG_TASK_CLAIMED, URL_TASK_CLAIM, URL_WATCH_AD, MSG_WATCHED_AD, URL_STOCKS, MSG_BALANCE 12 | 13 | 14 | class BotFarmer(BaseFarmer): 15 | 16 | name = 'orbitonx_bot' 17 | upgrades = {} 18 | info = {} 19 | levels = {} 20 | quests = {} 21 | tasks = [] 22 | next_claim = None 23 | app_extra = "friendId102796269" 24 | tokens = {} 25 | refreshable_token = True 26 | codes_to_refresh = (401,) 27 | 28 | @property 29 | def initialization_data(self): 30 | return dict(peer=self.initiator.get_input_entity(self.name), 31 | app=InputBotAppShortName(self.initiator.get_input_entity(self.name), "orbitonx"), 32 | start_param=self.app_extra) 33 | 34 | def set_headers(self, *args, **kwargs): 35 | self.headers = HEADERS.copy() 36 | self.get = api_response(super().get) 37 | self.post = api_response(super().post) 38 | self.delete = api_response(super().delete) 39 | self.patch = api_response(super().patch) 40 | 41 | def set_start_time(self): 42 | timestamps = (self.portfolio['finishStaking'], self.info['adNextAvailableTime']) 43 | self.start_time = min(map(to_localtz_timestamp, timestamps)) + 5 44 | 45 | def prepare_auth_data(self, url): 46 | from urllib.parse import unquote, parse_qsl 47 | parsed = parse_qsl(unquote(unquote(url))) 48 | user = json.loads(parsed[0][-1].split('user=')[-1]) 49 | parsed.pop(0) 50 | parsed = dict(parsed) 51 | data = { 52 | "tgChatId": user['id'], 53 | "webAppInitData": { 54 | "user": user, 55 | "chat_instance": parsed['chat_instance'], 56 | "chat_type": parsed['chat_type'], 57 | "auth_date": parsed['auth_date'], 58 | "hash": parsed['hash'] 59 | }, 60 | "user": user 61 | } 62 | return data 63 | 64 | 65 | def authenticate(self, *args, **kwargs): 66 | auth_data = self.initiator.get_auth_data(**self.initialization_data) 67 | auth_data = self.prepare_auth_data(auth_data['url']) 68 | if response := self.post(URL_AUTH, json=auth_data): 69 | self.tokens = response['data'] 70 | self.headers['Authorization'] = f"Bearer {self.tokens['token']}" 71 | else: 72 | self.is_alive = False 73 | raise Exception(MSG_AUTH_ERROR) 74 | 75 | def refresh_token(self): 76 | self.initiator.connect() 77 | self.authenticate() 78 | self.initiator.disconnect() 79 | 80 | 81 | def sync(self): 82 | if response := self.get(URL_INFO): 83 | self.info = response['data'] 84 | 85 | def update_tasks(self): 86 | if response := self.get(URL_TASKS): 87 | self.tasks = response['data']['tasks'] 88 | 89 | def check_tasks(self): 90 | self.update_tasks() 91 | for task in self.tasks: 92 | if task['status'] == 'not started': 93 | response = self.post(URL_TASKS, json={'taskId': task['id']}) 94 | if response.get('status'): 95 | if self.get(URL_TASK_CLAIM.format(**task)).get('status'): 96 | self.log(MSG_TASK_CLAIMED.format(**task)) 97 | sleep(random() * 5) 98 | 99 | def watch_ad(self): 100 | while to_localtz_timestamp(self.info['adNextAvailableTime']) < time(): 101 | if response := self.get(URL_WATCH_AD): 102 | if response['data']['balance'] > self.info['balance']: 103 | self.info.update(response['data']) 104 | self.log(MSG_WATCHED_AD) 105 | sleep(random() * 20) 106 | else: 107 | break 108 | 109 | 110 | def update_quests(self): 111 | if response := self.get(URL_QUESTS): 112 | self.quests.update(response['data']) 113 | 114 | @property 115 | def portfolio(self): 116 | return self.quests['quest']['portfolios'][0] 117 | 118 | def claim_or_farm(self): 119 | self.update_quests() 120 | # claim 121 | if self.portfolio['finishStaking'] and to_localtz_timestamp(self.portfolio['finishStaking']) < time() and not self.portfolio['active']: 122 | if response := self.patch(URL_STAKING_CLAIM, json={}): 123 | self.quests = response['data'] 124 | self.log(MSG_STAKING_CLAIMED.format(**self.quests['quest'])) 125 | self.update_quests() 126 | # tap 127 | if self.portfolio['active']: 128 | payload = dict(coins=[{'id': coin['id'], 'progress': 100} for coin in self.portfolio['coins']]) 129 | payload['energy'] = 500 130 | response = self.patch(URL_TAP, json=payload) 131 | if response: 132 | self.log(MSG_STAKING_TAP) 133 | self.update_quests() 134 | 135 | def select_exchange(self): 136 | if not self.info['stoke']['id'] not in (8, 9): 137 | self.patch(URL_STOCKS, json={'stockId': 9}) 138 | self.sync() 139 | 140 | @property 141 | def balance(self): 142 | return self.info['balance'] 143 | 144 | def farm(self): 145 | self.sync() 146 | self.select_exchange() 147 | self.claim_or_farm() 148 | self.check_tasks() 149 | self.watch_ad() 150 | self.sync() 151 | self.log(MSG_BALANCE.format(balance=self.balance)) 152 | 153 | -------------------------------------------------------------------------------- /bots/orbitonx/strings.py: -------------------------------------------------------------------------------- 1 | URL_INIT = "https://game.orbitonx.com/" 2 | URL_AUTH = "https://api.orbitonx.com/api/auth" # POST payload 3 | URL_BALANCE = "https://api.orbitonx.com/api/users/balance" # GET 4 | URL_INFO = "https://api.orbitonx.com/api/users/info" # GET 5 | URL_REWARD = "https://api.orbitonx.com/api/users/reward" # POST None 6 | URL_STOCKS = "https://api.orbitonx.com/api/general/stocks" # GET 7 | URL_QUESTS = "https://api.orbitonx.com/api/user-quests" # GET 8 | URL_STAKING_CLAIM = "https://api.orbitonx.com/api/user-coins/collect-reward" # PATCH 9 | URL_TAP = "https://api.orbitonx.com/api/user-coins" # POST payload 10 | URL_TASKS = "https://api.orbitonx.com/api/user-tasks" # GET 11 | URL_TASK_CLAIM = "https://api.orbitonx.com/api/user-tasks/get-bonus/{id}" # GET 12 | URL_START_TASK = "https://api.orbitonx.com/api/user-tasks" # POST 13 | URL_WATCH_AD = "https://api.orbitonx.com/api/users/increase-balance" # GET LOL 14 | URL_CARDS_LIST = "https://api.orbitonx.com/api/boost-cards" 15 | URL_MY_CARDS = "https://api.orbitonx.com/api/user-boost-cards" 16 | URL_COMBOS = "https://api.orbitonx.com/api/combos" 17 | URL_STOCKS = "https://api.orbitonx.com/api/general/stocks" 18 | 19 | MSG_AUTH_ERROR = "Ошибка аутентификации" 20 | MSG_STAKING_CLAIMED = "Собрал за стейкинг {rewardFromStacking}" 21 | MSG_STAKING_STARTED = "Начал стейкать" 22 | MSG_STAKING_TAP = "Натапал на стейкинг" 23 | MSG_TASK_CLAIMED = "Выполнил таску на {capacity} $RCT" 24 | MSG_WATCHED_AD = "Посмотрел рекалму ;) получил 10 $RCT" 25 | MSG_BALANCE = "Текущий баланс: {balance}" 26 | 27 | HEADERS = { 28 | 'accept': 'application/json, text/plain, */*', 29 | 'accept-language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7,cy;q=0.6', 30 | 'cache-control': 'no-cache', 31 | 'content-type': 'application/json', 32 | 'origin': 'https://game.orbitonx.com', 33 | 'pragma': 'no-cache', 34 | 'priority': 'u=1, i', 35 | 'referer': 'https://game.orbitonx.com/', 36 | 'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"', 37 | 'sec-ch-ua-mobile': '?0', 38 | 'sec-ch-ua-platform': '"Windows"', 39 | 'sec-fetch-dest': 'empty', 40 | 'sec-fetch-mode': 'cors', 41 | 'sec-fetch-site': 'same-site', 42 | 'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36', 43 | 'x-timezone': 'Europe/Moscow', 44 | } 45 | -------------------------------------------------------------------------------- /bots/race/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /bots/race/client.py: -------------------------------------------------------------------------------- 1 | 2 | from random import randrange, random 3 | from time import time, sleep 4 | from threading import Thread 5 | from bots.base.base import BaseFarmer 6 | from bots.base.utils import to_localtz_timestamp, api_response 7 | from .strings import HEADERS, URL_DRIVE, URL_INFO, URL_INIT, MSG_BALANCE, URL_RESTORE_FUEL 8 | 9 | 10 | class BotFarmer(BaseFarmer): 11 | name = "racememe_bot" 12 | extra_code = "r_102796269" 13 | init_data = None 14 | riding_thread = None 15 | debug = False 16 | initialization_data = dict(peer=name, bot=name, url=URL_INIT) 17 | 18 | def set_headers(self, *args, **kwargs): 19 | self.headers = HEADERS.copy() 20 | self.get = api_response(super().get) 21 | self.post = api_response(super().post) 22 | 23 | def authenticate(self, *args, **kwargs): 24 | auth_data = self.initiator.get_auth_data(**self.initialization_data) 25 | self.init_data = auth_data['url'].split('tgWebAppData=')[-1].split('&')[0] 26 | 27 | def refresh_token(self): 28 | self.initiator.connect() 29 | self.authenticate() 30 | self.initiator.disconnect() 31 | 32 | @property 33 | def ready_to_ride(self): 34 | self.sync() 35 | traffic_light = self.info['user']['trafficLight'] 36 | return traffic_light['trafficLightState'] == 'green' and traffic_light['remainingTime'] > 1500 37 | 38 | @property 39 | def fuel(self): 40 | return self.info['user']['fuel']['lastFuelAmount'] 41 | 42 | def restore_fuel(self): 43 | fuel = self.info['user']['fuel'] 44 | if fuel['numberOfRestores'] != fuel['maxNumberOfRestores']: 45 | return bool(self.get(URL_RESTORE_FUEL.format(init_data=self.init_data))) 46 | 47 | def set_start_time(self): 48 | self.start_time = time() + 3600 49 | 50 | def ride(self): 51 | self.sync() 52 | if not self.ready_to_ride: 53 | return 54 | liters = round(randrange(0, 3) + random(), 1) 55 | if liters <= self.fuel or self.restore_fuel(): 56 | meters = liters * 100 - randrange(0, 6) 57 | payload = {"numberOfMeters": meters, "numberOfLiters": liters} 58 | response = self.post(URL_DRIVE.format(init_data=self.init_data), json=payload, return_codes=(520, )) 59 | 60 | def ride_in_thread(self): 61 | for _ in range(1000): 62 | self.ride() 63 | sleep(3) 64 | 65 | def start_riding_thread(self): 66 | if not self.riding_thread or not self.riding_thread.is_alive(): 67 | self.riding_thread = Thread(target=self.ride_in_thread) 68 | self.riding_thread.start() 69 | 70 | def sync(self): 71 | response = self.get(URL_INFO.format(init_data=self.init_data), return_codes=(520, )) 72 | if response: 73 | self.info = response 74 | 75 | def farm(self): 76 | self.start_riding_thread() 77 | self.sync() 78 | self.log(MSG_BALANCE.format(meters=self.info['user']['distance']['lastDistanceAmount'])) 79 | pass 80 | -------------------------------------------------------------------------------- /bots/race/strings.py: -------------------------------------------------------------------------------- 1 | URL_INIT = "https://racing-tg.web.app/" 2 | URL_INFO = "https://racing-tg-p12o.onrender.com/user?tgInitData={init_data}" 3 | URL_DRIVE = "https://racing-tg-p12o.onrender.com/race/addDistance?tgInitData={init_data}" 4 | URL_RESTORE_FUEL = "https://racing-tg-p12o.onrender.com/booster/restoreFullTank?tgInitData={init_data}" 5 | 6 | MSG_PROFILE = "Обновил профиль" 7 | MSG_CLAIM = "Собрал нафармленное" 8 | MSG_BALANCE = "Пройдено {meters} метров" 9 | 10 | HEADERS = { 11 | 'accept': '*/*', 12 | 'accept-language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7,cy;q=0.6', 13 | 'cache-control': 'no-cache', 14 | 'origin': 'https://racing-tg.web.app', 15 | 'pragma': 'no-cache', 16 | 'priority': 'u=1, i', 17 | 'referer': 'https://racing-tg.web.app/', 18 | 'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"', 19 | 'sec-ch-ua-mobile': '?1', 20 | 'sec-ch-ua-platform': '"Android"', 21 | 'sec-fetch-dest': 'empty', 22 | 'sec-fetch-mode': 'cors', 23 | 'sec-fetch-site': 'cross-site', 24 | } 25 | -------------------------------------------------------------------------------- /bots/simple/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TotalAwesome/BotFarmFactory/a014a70f66abbe1a46c9796847cd8813764978d1/bots/simple/__init__.py -------------------------------------------------------------------------------- /bots/simple/client.py: -------------------------------------------------------------------------------- 1 | import string 2 | from random import random, randrange, shuffle, choice 3 | from bots.base.base import BaseFarmer 4 | from time import time, sleep 5 | from bots.simple.utils import get_sorted_upgrades 6 | from bots.simple.config import BUY_UPGRADES, PERCENT_TO_SPEND 7 | from bots.simple.strings import HEADERS, URL_INIT, URL_PROFILE, URL_TAP, URL_GET_MINING_BLOCKS, URL_FRIENDS, \ 8 | URL_GET_TASK_LIST, URL_CLAIM_FARMED, URL_START_FARM, URL_CHECK_TASK, URL_START_TASK, URL_CLAIM_FRIENDS, \ 9 | URL_BUY_UPGRADE, URL_CLAIM_SPIN, MSG_PROFILE_UPDATE, MSG_TAP, MSG_START_FARMING, MSG_BUY_UPGRADE, SPIN_TYPES, \ 10 | MSG_SPIN, MSG_START_TASK, MSG_CLAIM_FARM, MSG_CLAIM_REFS, MSG_STATE, URL_COLLECTIONS, URL_GET_COLLECTION, \ 11 | URL_CLAIM_CARD, MSG_CLAIMED_CARD, URL_REGISTER, EMAIL_DOMAINS, MSG_REGISTRATION, URL_SET_EMAIL, MSG_TASK_CLAIMED 12 | 13 | 14 | class BotFarmer(BaseFarmer): 15 | 16 | name = 'simple_tap_bot' 17 | 18 | initialization_data = dict(peer=name, bot=name, url=URL_INIT) 19 | payload_base = {'userId': None, 'authData': None, } 20 | initiator = None 21 | upgrades = {} 22 | info = {} 23 | freezed_balance = None 24 | extra_code = "1718085881160" 25 | 26 | def freeze_balance(self): 27 | self.freezed_balance = self.info['balance'] 28 | 29 | def set_headers(self, *args, **kwargs): 30 | self.headers = HEADERS.copy() 31 | 32 | def authenticate(self, *args, **kwargs): 33 | self.payload_base = self.initiator.get_auth_data(**self.initialization_data) 34 | 35 | def api_call(self, url, payload=None): 36 | payload = payload or {} 37 | payload.update(self.payload_base) 38 | result = self.post(url, json=payload, return_codes=(400, 429)) 39 | if result.status_code == 200: 40 | return result.json() 41 | elif result.status_code == 429: 42 | delay = int(result.headers.get('retry-after')) 43 | self.start_time = time() + delay 44 | raise Exception(f'error 429: sleeping {delay} seconds') 45 | else: 46 | self.log(str(result.status_code) + ' ' + result.text) 47 | return {} 48 | 49 | def update_profile(self): 50 | self.info = self.api_call(URL_PROFILE).get('data', {}) 51 | self.log(MSG_PROFILE_UPDATE) 52 | if not self.info['hasEmail']: 53 | self.register() 54 | 55 | def register(self): 56 | charmap = string.ascii_letters + '_.-' 57 | email = choice(EMAIL_DOMAINS).format( 58 | ''.join(str(choice(charmap)) for _ in range(randrange(6, 12))) 59 | ) 60 | payload = dict(**self.payload_base, refCode=self.extra_code, email=email) 61 | self.post(URL_REGISTER, json=payload) 62 | self.post(URL_SET_EMAIL, json=dict(email=email, **self.payload_base)) 63 | self.log(MSG_REGISTRATION) 64 | 65 | @property 66 | def mine_per_hour(self): 67 | return self.info['activeFarmingPerSec'] * 3600 68 | 69 | @property 70 | def taps_per_hour(self): 71 | return self.info['addTapPerSecond'] * 3600 72 | 73 | def set_start_time(self): 74 | taps_recover_seconds = self.info.get('maxAvailableTaps') / self.info.get('addTapPerSecond') 75 | farming_seconds = self.info['maxFarmingSecondSec'] - self.info['activeFarmingSeconds'] 76 | self.start_time = time() + min(taps_recover_seconds, farming_seconds) 77 | 78 | def tap(self): 79 | if available_taps := self.info['availableTaps']: 80 | if taps := int((available_taps // self.info['tapSize']) * self.info['tapSize']): 81 | payload = self.payload_base.copy() 82 | payload['count'] = taps 83 | self.api_call(URL_TAP, payload=payload) 84 | self.log(MSG_TAP.format(taps=taps)) 85 | 86 | def start_task(self, task): 87 | payload = dict(id=task['id'], type=task['type'], **self.payload_base) 88 | self.api_call(URL_START_TASK, payload=payload) 89 | self.log(MSG_START_TASK.format(**task)) 90 | 91 | 92 | def check_task(self, task): 93 | payload = dict(id=task['id'], type=task['type'], **self.payload_base) 94 | result = self.api_call(URL_CHECK_TASK, payload=payload) 95 | if result['result'] == 'OK': 96 | self.log(MSG_TASK_CLAIMED.format(**task)) 97 | 98 | def claim_tasks(self): 99 | task_list = self.api_call(URL_GET_TASK_LIST, payload=dict(platform=1, lang='en')) 100 | for task in task_list['data']['social']: 101 | if task['status'] == 1: 102 | self.start_task(task) 103 | sleep(randrange(5, 10)) 104 | elif task['status'] == 2: 105 | self.check_task(task) 106 | sleep(randrange(5, 10)) 107 | 108 | def is_it_not_expensive(self, price): 109 | min_dst_balance = self.freezed_balance * (1 - PERCENT_TO_SPEND / 100) 110 | return self.info["balance"] - price >= min_dst_balance 111 | 112 | def buy_upgrade(self, upgrade): 113 | level = upgrade['currentLevel'] + 1 114 | mine_id = upgrade['mineId'] 115 | payload = self.payload_base.copy() 116 | payload.update(dict(level=level, mineId=mine_id)) 117 | self.update_profile() 118 | if self.is_it_not_expensive(upgrade['nextPrice']): 119 | self.api_call(URL_BUY_UPGRADE, payload=payload) 120 | self.log(MSG_BUY_UPGRADE.format( 121 | name=upgrade['mineId'], 122 | level=upgrade['currentLevel'] + 1, 123 | price=upgrade['nextPrice'], 124 | payback=upgrade['payback'], 125 | )) 126 | return True 127 | else: 128 | return False 129 | 130 | def claim_spin(self): 131 | for _ in range(self.info.get('spinCount', 0)): 132 | payload = self.payload_base.copy() 133 | payload.update(dict(amount=0, frontCoef=random() * 1000)) 134 | result = self.api_call(URL_CLAIM_SPIN, payload=payload) 135 | tap_type = SPIN_TYPES.get(result['data']['spinType'], 136 | result['data']['spinType']) 137 | self.log(MSG_SPIN.format(type=tap_type, 138 | amount=result['data']['amount'])) 139 | sleep(randrange(1, 5)) 140 | 141 | def update_upgrades(self): 142 | self.upgrades = self.api_call(URL_GET_MINING_BLOCKS).get('data', {}).get('mines', []) 143 | 144 | def friends(self): 145 | self.api_call(URL_FRIENDS) 146 | 147 | def tasks(self): 148 | self.api_call(URL_GET_TASK_LIST) 149 | 150 | def start_farm(self): 151 | if self.info['activeFarmingSeconds'] == 0 and self.info['activeFarmingBalance'] == 0: 152 | self.api_call(URL_START_FARM) 153 | self.log(MSG_START_FARMING) 154 | self.update_profile() 155 | 156 | def claim_farmed(self): 157 | if self.info['activeFarmingSeconds'] == self.info['maxFarmingSecondSec']: 158 | self.api_call(URL_CLAIM_FARMED) 159 | self.log(MSG_CLAIM_FARM.format(amount=self.info['activeFarmingBalance'])) 160 | self.start_farm() 161 | self.update_profile() 162 | 163 | def claim_friends(self): 164 | if claimed := self.info.get('refBalance'): 165 | self.api_call(URL_CLAIM_FRIENDS) 166 | self.log(MSG_CLAIM_REFS.format(amount=claimed)) 167 | 168 | def buy_taplimit_upgrade(self): 169 | self.update_upgrades() 170 | if upgrades_to_buy := get_sorted_upgrades(self.upgrades, upgrade_type=1): 171 | upgrade = upgrades_to_buy[0] 172 | if self.is_it_not_expensive(upgrade['nextPrice']): 173 | self.buy_upgrade(upgrade) 174 | 175 | def buy_upgrades(self): 176 | while True: 177 | self.update_upgrades() 178 | if upgrades_to_buy := get_sorted_upgrades(self.upgrades): 179 | upgrade = upgrades_to_buy[0] 180 | if not self.buy_upgrade(upgrade): 181 | break 182 | sleep(1) 183 | else: 184 | break 185 | 186 | 187 | def claim_cards(self): 188 | collections = self.api_call(URL_COLLECTIONS, payload={'lang': 'ru'}) 189 | for collection in collections.get("data", []): 190 | if collection['status'] == 1: 191 | payload = {'collectionId': collection['id'], 'lang': 'ru'} 192 | collection_cards = self.api_call(URL_GET_COLLECTION, payload=payload) 193 | for card in collection_cards.get('data', []): 194 | if card['status'] == 1: 195 | payload = {'cardId': card['id'], 'collectionId': collection['id'], 'lang': 'ru'} 196 | result = self.api_call(URL_CLAIM_CARD, payload=payload) 197 | if result['result'] == 'OK': 198 | self.log(MSG_CLAIMED_CARD.format(**card)) 199 | sleep(random() * random() * 10) 200 | 201 | def farm(self): 202 | self.update_profile() 203 | actions = [self.claim_tasks, 204 | self.claim_cards, 205 | self.claim_farmed, 206 | self.claim_friends, 207 | self.claim_spin, 208 | self.tap, ] 209 | shuffle(actions) 210 | for action in actions: 211 | action() 212 | sleep(random() * random() * 10) 213 | self.start_farm() 214 | if BUY_UPGRADES: 215 | self.freeze_balance() 216 | self.buy_upgrades() 217 | self.buy_taplimit_upgrade() 218 | self.update_profile() 219 | self.log(MSG_STATE.format(balance=self.info['balance'], 220 | mine_per_hour=self.mine_per_hour, 221 | taps_per_hour=self.taps_per_hour)) 222 | -------------------------------------------------------------------------------- /bots/simple/config.py: -------------------------------------------------------------------------------- 1 | BUY_UPGRADES = True # Покупать ли апгрейды 2 | PERCENT_TO_SPEND = 100 # Какой процент от депозита должен остаться после покупок 3 | -------------------------------------------------------------------------------- /bots/simple/strings.py: -------------------------------------------------------------------------------- 1 | URL_GET_MINING_BLOCKS = "https://api.simple.app/api/v1/public/telegram/get-mining-blocks/" # POST 2 | URL_GET_TASK_LIST = "https://api.simple.app/api/v1/public/telegram/get-task-list-2/" # POST 3 | URL_START_TASK = "https://api.simple.app/api/v1/public/telegram/start-task-start-2/" # POST {userid, auth_data, type, id} 4 | URL_CHECK_TASK = "https://api.simple.app/api/v1/public/telegram/check-task-check-2/" # POST {userid, auth_data, type, id} 5 | URL_BUY_UPGRADE = "https://api.simple.app/api/v1/public/telegram/buy-mining-block/" # POST {level, mineid} 6 | URL_CLAIM_FRIENDS = "https://api.simple.app/api/v1/public/telegram/claim_friends/" # POST 7 | URL_CLAIM_SPIN = "https://api.simple.app/api/v1/public/telegram/claim-spin/" # POST {userId, authData, frontCoef, amount} 8 | URL_START_FARM = "https://api.simple.app/api/v1/public/telegram/activate/" # POST 9 | URL_REGISTER = "https://apii.simple.app/api/v1/public/telegram/register/" # POST authData, email, refCode, userId 10 | URL_SET_EMAIL = "https://apii.simple.app/api/v1/public/telegram/set-client-email/" # POST 11 | URL_CLAIM_FARMED = "https://api.simple.app/api/v1/public/telegram/claim/" # POST 12 | URL_FRIENDS = "https://api.simple.app/api/v1/public/telegram/friends/" # POST 13 | URL_SPIN = "https://api.simple.app/api/v1/public/telegram/claim-spin/" 14 | URL_PROFILE = "https://api.simple.app/api/v1/public/telegram/profile/" # POST 15 | URL_TAP = "https://api.simple.app/api/v1/public/telegram/tap/" # POST {userid, authdata, count} 16 | URL_INIT = "https://simpletap.app/version_05/" 17 | URL_COLLECTIONS = "https://api.simple.app/api/v1/public/telegram-collection/get-collections/" # POST {userid, authdata, lang} 18 | URL_GET_COLLECTION = "https://api.simple.app/api/v1/public/telegram-collection/get-collection-cards/" # POST +collectionId 19 | URL_CLAIM_CARD = "https://api.simple.app/api/v1/public/telegram-collection/card-claim/" # POST cardId: 78 collectionId : "introduction_to_blockchain" 20 | 21 | 22 | MSG_PROFILE_UPDATE = "Обновление профиля" 23 | MSG_TAP = "Натапал {taps} монет" 24 | MSG_START_FARMING = "Начал фармить" 25 | MSG_START_TASK = "Запустил таску ({title})" 26 | MSG_TASK_CLAIMED = "Выполнил таску ({title}) на {bonus} SMPL" 27 | MSG_BUY_UPGRADE = "Прокачал: {name} ({level}) цена: {price} окупаемость: {payback}" 28 | MSG_SPIN = "Крутанул рулетку, получил: {type} кол-во: {amount}" 29 | MSG_CLAIM_FARM = "Собрал нафармленное: {amount}" 30 | MSG_CLAIM_REFS = "Собрал нафармленное рефами: {amount}" 31 | MSG_STATE = "Баланс: {balance} | Прибыль в час: {mine_per_hour} | тапов в час: {taps_per_hour}" 32 | MSG_CLAIMED_CARD = "Склеймил карту (профит {amount}): {title}" 33 | MSG_REGISTRATION = "Зарегистрировался..." 34 | 35 | class UpgradeTypes: 36 | TAPS_LIMIT = 1 37 | PASSIVE_EARN = 2 38 | TAP_SIZE = 3 39 | 40 | SPIN_TYPES = { 41 | 0: "лимит тапов", 42 | 1: "добыча", 43 | 2: "размер тапа", 44 | 3: "монеты", 45 | } 46 | 47 | EMAIL_DOMAINS = ('{}@yahoo.com', 48 | '{}@gmail.com', 49 | '{}@mail.ru', 50 | '{}@rambler.ru', 51 | '{}@outlook.com') 52 | 53 | HEADERS = { 54 | 'Host' : 'api.simple.app', 55 | 'sec-ch-ua' : '"Chromium";v="122", "Not(A:Brand";v="24", "Android WebView";v="122"', 56 | 'accept' : 'application/json, text/plain, */*', 57 | 'content-type' : 'application/json', 58 | 'sec-ch-ua-mobile' : '?1', 59 | 'user-agent' : 'Mozilla/5.0 (Linux; Android 11; Samsung Galaxy S22; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.64 Mobile Safari/537.36', 60 | 'sec-ch-ua-platform' : 'Android', 61 | 'origin' : 'https://simpletap.app', 62 | 'x-requested-with' : 'org.telegram.messenger', 63 | 'sec-fetch-site' : 'cross-site', 64 | 'sec-fetch-mode' : 'cors', 65 | 'sec-fetch-dest' : 'empty', 66 | 'referer' : 'https://simpletap.app/', 67 | 'accept-language' : 'ru,ru-RU;q=0.9,en-US;q=0.8,en;q=0.7', 68 | } 69 | -------------------------------------------------------------------------------- /bots/simple/utils.py: -------------------------------------------------------------------------------- 1 | 2 | def get_available_upgrades(upgrades, upgrade_type = 2): 3 | current_levels = {mine['mineId']: mine['currentLevel'] for mine in upgrades} 4 | available_upgrades = [] 5 | for upgrade in upgrades: 6 | if upgrade.get('currentLevel', -1) == upgrade.get('maxLevel'): 7 | continue 8 | if upgrade['type'] == upgrade_type: 9 | upgrade['payback'] = upgrade['nextPrice'] / (upgrade['nextVolume'] / 8) 10 | upgrade.pop('description', None) 11 | dependency_id = upgrade.get('dependencyMineId') 12 | dependency_level = upgrade.get('dependencyMineLevel') 13 | if current_levels.get(dependency_id, 0) >= dependency_level: 14 | available_upgrades.append(upgrade) 15 | return available_upgrades 16 | 17 | def get_sorted_upgrades(upgrades, upgrade_type = 2): 18 | sorted_upgrades = sorted(get_available_upgrades(upgrades, upgrade_type), 19 | key=lambda x: x['payback']) 20 | return sorted_upgrades[:10] 21 | -------------------------------------------------------------------------------- /bots/solstone/client.py: -------------------------------------------------------------------------------- 1 | from time import sleep, time 2 | from random import random, shuffle 3 | from bots.base.base import BaseFarmer 4 | from bots.base.utils import to_localtz_timestamp, api_response 5 | from bots.solstone.strings import HEADERS, URL_AUTH, URL_TASKS, URL_CLAIM_TASK, URL_INIT, URL_CLAIM_FARMED, \ 6 | URL_START_FARM, MSG_CLAIM_FARMED, MSG_FARMING_STARTED, MSG_TASK_CLAIMED, URL_REFS_INFO, URL_CLAIM_REFS, \ 7 | MSG_CLAIM_REFS 8 | from .utils import utc_timestamp 9 | 10 | 11 | class BotFarmer(BaseFarmer): 12 | name = "solstonebot" 13 | extra_code = "102796269" 14 | initialization_data = dict(peer=name, bot=name, url=URL_INIT) 15 | base_payload = None 16 | time_shift = (8 * 60 * 60 + 10) * 1000 17 | 18 | def timestamp(self): 19 | return int(utc_timestamp() * 1000) 20 | 21 | def set_headers(self, *args, **kwargs): 22 | self.headers = HEADERS.copy() 23 | self.get = api_response(super().get) 24 | self.post = api_response(super().post) 25 | self.delete = api_response(super().delete) 26 | 27 | def authenticate(self, *args, **kwargs): 28 | auth_data = self.initiator.get_auth_data(**self.initialization_data)["authData"] 29 | self.base_payload = {'initData': auth_data, 'project': 'SolStone'} 30 | self.info = self.post(URL_AUTH, json=self.base_payload) 31 | 32 | def get_tasks(self): 33 | return self.get(URL_TASKS) 34 | 35 | def claim_tasks(self): 36 | if not (tasks := self.get_tasks()): 37 | return 38 | shuffle(tasks) 39 | for task in tasks: 40 | if task['id'] not in self.info['completed_quest_ids']: 41 | payload = self.base_payload.copy() 42 | payload.update(questId=task['id']) 43 | self.post(URL_CLAIM_TASK, json=payload) 44 | self.info['completed_quest_ids'].append(task['id']) 45 | self.log(MSG_TASK_CLAIMED.format(amount=task['points_reward'])) 46 | sleep(random() * 10) 47 | 48 | def claim_or_start_farming(self): 49 | farming_started = int(self.info['farm_started_at']) if self.info.get('farm_started_at') else None 50 | if farming_started and self.timestamp() > farming_started + self.time_shift: 51 | self.debug(f"{farming_started=} {self.timestamp()} {self.time_shift + farming_started=}") 52 | farming_started = None 53 | response = self.post(URL_CLAIM_FARMED, json=self.base_payload, return_codes=(400,)) 54 | if response: 55 | self.log(MSG_CLAIM_FARMED) 56 | ids = list(map(int, response["completed_quest_ids"].strip(',').split(','))) 57 | response["completed_quest_ids"] = ids 58 | self.info.update(response) 59 | if not farming_started: 60 | payload = self.base_payload.copy() 61 | payload['startedAt'] = self.timestamp() 62 | farm_response = self.post(URL_START_FARM, json=payload) 63 | if farm_response: 64 | self.log(MSG_FARMING_STARTED) 65 | self.info['farm_started_at'] = farm_response['started_at'] 66 | 67 | def set_start_time(self): 68 | self.start_time = (int(self.info.get('farm_started_at')) + self.time_shift) / 1000 69 | 70 | def claim_refs(self): 71 | if response := self.get(URL_REFS_INFO.format(**self.info)): 72 | total_farmed = sum(int(ref['points']) for ref in response) 73 | if total_farmed - int(self.info.get('ref_points_claimed', 0)): 74 | response = self.post(URL_CLAIM_REFS, json=self.base_payload) 75 | if response: 76 | self.info['ref_points_claimed'] = int(self.info.get('ref_points_claimed', 0)) + response['claimed_points'] 77 | self.log(MSG_CLAIM_REFS.format(amount=response['claimed_points'])) 78 | 79 | 80 | def farm(self): 81 | self.claim_tasks() 82 | self.claim_or_start_farming() 83 | self.claim_refs() 84 | 85 | -------------------------------------------------------------------------------- /bots/solstone/strings.py: -------------------------------------------------------------------------------- 1 | URL_INIT = "https://solstone-app.gleam.bot" 2 | URL_AUTH = "https://solstone-api.gleam.bot/auth" 3 | URL_TASKS = "https://solstone-api.gleam.bot/quests?project=SolStone" 4 | URL_CLAIM_TASK = "https://solstone-api.gleam.bot/complete-quest" 5 | URL_START_FARM = "https://solstone-api.gleam.bot/start-farming" 6 | URL_CLAIM_FARMED = "https://solstone-api.gleam.bot/claim" 7 | URL_CLAIM_REFS = "https://solstone-api.gleam.bot/claim-ref-rewards" 8 | URL_REFS_INFO = "https://solstone-api.gleam.bot/users/{tg_id}/invitees?project=SolStone" 9 | 10 | HEADERS = { 11 | 'accept': 'application/json, text/plain, */*', 12 | 'accept-language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7,cy;q=0.6', 13 | 'cache-control': 'no-cache', 14 | 'content-type': 'application/json', 15 | 'ngrok-skip-browser-warning': '69420', 16 | 'origin': 'https://solstone-app.gleam.bot', 17 | 'pragma': 'no-cache', 18 | 'priority': 'u=1, i', 19 | 'referer': 'https://solstone-app.gleam.bot/', 20 | 'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"', 21 | 'sec-ch-ua-mobile': '?1', 22 | 'sec-ch-ua-platform': '"Android"', 23 | 'sec-fetch-dest': 'empty', 24 | 'sec-fetch-mode': 'cors', 25 | 'sec-fetch-site': 'same-site', 26 | 'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRXN8N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36', 27 | } 28 | 29 | MSG_CLAIM_FARMED = "Собрал нафармленное" 30 | MSG_FARMING_STARTED = "Начал фармить" 31 | MSG_TASK_CLAIMED = "Собрал за таску {amount}" 32 | MSG_CLAIM_REFS = "Собрал за рефов {amount}" -------------------------------------------------------------------------------- /bots/solstone/utils.py: -------------------------------------------------------------------------------- 1 | from datetime import timezone 2 | import datetime 3 | 4 | def utc_timestamp(): 5 | now = datetime.datetime.now(timezone.utc) 6 | utc_time = now.replace(tzinfo=timezone.utc) 7 | return utc_time.timestamp() 8 | -------------------------------------------------------------------------------- /bots/tapcoins/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /bots/tapcoins/client.py: -------------------------------------------------------------------------------- 1 | """ 2 | Author: Eyn 3 | Date: 17-07-2024 4 | 5 | """ 6 | import random 7 | from time import time, sleep 8 | 9 | from bots.base.base import BaseFarmer 10 | from bots.tapcoins.config import BUY_UPGRADES, UPGRADES_COUNT 11 | from bots.tapcoins.strings import HEADERS, URL_INIT, URL_LOGIN, URL_CARDS_CATEGORIES, URL_CARDS_LIST, \ 12 | URL_CARDS_UPGRADE, URL_LUCKY_BOUNTY, MSG_NO_CARDS_TO_UPGRADE, \ 13 | MSG_CARD_UPGRADED, MSG_NOT_ENOUGH_COINS, MSG_CARD_UPGRADED_COMBO, URL_DAILY, URL_DAILY_COMPLETE, \ 14 | MSG_LOGIN_BONUS_COMPLETE, URL_USER_INFO, MSG_UPGRADING_CARDS, MSG_UPGRADE_COMPLETE, MSG_MAX_UPGRADES_REACHED, \ 15 | URL_REFRESH, MSG_CURRENT_BALANCE, MSG_HOUR_EARNINGS, URL_GET_TASKS, URL_COMPLETE_TASK, MSG_TASK_COMPLETED 16 | 17 | DEFAULT_EST_TIME = 60 * 10 18 | 19 | 20 | class BotFarmer(BaseFarmer): 21 | name = "tapcoinsbot" 22 | token = None 23 | balance = None 24 | hours_earnings = None 25 | extra_code = 'ref_QjG2zG' 26 | refreshable_token = True 27 | codes_to_refresh = (401,) 28 | initialization_data = dict(peer=name, bot=name, url=URL_INIT, start_param=extra_code) 29 | 30 | def set_headers(self, *args, **kwargs): 31 | self.headers = HEADERS.copy() 32 | 33 | def authenticate(self, *args, **kwargs): 34 | init_data = self.initiator.get_auth_data(**self.initialization_data) 35 | 36 | data = { 37 | 'initData': init_data["authData"], 38 | 'inviteCode': 'QjG2zG', 39 | 'groupId': '' 40 | } 41 | 42 | result = self.post(URL_LOGIN, data=data) 43 | if result.status_code == 200: 44 | json_data = result.json() 45 | if 'data' in json_data and 'token' in json_data['data']: 46 | self.token = json_data['data']['token'] 47 | self.is_alive = True 48 | else: 49 | self.is_alive = False 50 | 51 | def set_start_time(self): 52 | if BUY_UPGRADES: 53 | try: 54 | cards = self.get_cards() 55 | if not cards: 56 | self.log(MSG_NO_CARDS_TO_UPGRADE) 57 | return 58 | 59 | cards = sorted(cards, key=lambda x: x['upgrade_earnings'] / x['upgrade_cost'], reverse=True) 60 | first_card = cards[0] 61 | 62 | self.get_balance(False) 63 | self.get_hour_earnings(False) 64 | 65 | if self.balance >= first_card['upgrade_cost']: 66 | self.start_time = time() + random.randint(300, 400) 67 | else: 68 | earnings_per_second = round(self.hours_earnings / 3600) 69 | 70 | time_to_upgrade = round(first_card['upgrade_cost'] / earnings_per_second) + random.randint(60, 120) 71 | 72 | self.start_time = time() + time_to_upgrade 73 | except Exception as e: 74 | est_time = DEFAULT_EST_TIME 75 | self.start_time = time() + est_time 76 | else: 77 | est_time = DEFAULT_EST_TIME 78 | self.start_time = time() + est_time 79 | 80 | def upgrade_cards(self): 81 | if BUY_UPGRADES: 82 | self.log(MSG_UPGRADING_CARDS) 83 | 84 | upgraded_cards = 0 85 | upgrades_count = UPGRADES_COUNT if UPGRADES_COUNT != 0 else 99999 86 | 87 | while True: 88 | if upgraded_cards >= upgrades_count: 89 | self.log(MSG_MAX_UPGRADES_REACHED.format(limit=upgrades_count)) 90 | break 91 | 92 | cards = self.get_cards() 93 | if not cards: 94 | self.log(MSG_NO_CARDS_TO_UPGRADE) 95 | break 96 | 97 | cards = sorted(cards, key=lambda x: x['upgrade_earnings'] / x['upgrade_cost'], reverse=True) 98 | 99 | self.get_balance(False) 100 | 101 | upgraded = False 102 | 103 | for card in cards: 104 | if self.balance >= card['upgrade_cost']: 105 | self.post(URL_CARDS_UPGRADE, {'taskId': card['id'], '_token': self.token}) 106 | upgraded = True 107 | 108 | level = card['current_level'] + 1 109 | 110 | self.log(MSG_CARD_UPGRADED.format(name=card['name'], level=level, cost=card['upgrade_cost'])) 111 | upgraded_cards += 1 112 | 113 | break 114 | 115 | if not upgraded: 116 | self.log(MSG_NOT_ENOUGH_COINS) 117 | break 118 | 119 | self.log(MSG_UPGRADE_COMPLETE) 120 | 121 | def get_cards(self): 122 | categories_response = self.post(URL_CARDS_CATEGORIES, data={'_token': self.token}) 123 | categories_json = categories_response.json() 124 | 125 | cards = [] 126 | 127 | for category in categories_json['data']: 128 | cards_response = self.post(URL_CARDS_LIST, {'categoryId': category['id'], '_token': self.token}) 129 | cards_json = cards_response.json() 130 | 131 | for card in cards_json['data']: 132 | if card['upgradable']: 133 | cards.append(card) 134 | return cards 135 | 136 | def get_bounty(self): 137 | data = { 138 | '_token': self.token 139 | } 140 | 141 | lucky_response = self.post(URL_LUCKY_BOUNTY, data=data) 142 | 143 | lucky_data = lucky_response.json() 144 | lucky_data_cards = lucky_data['data']['currents'] 145 | lucky_sum = 0 146 | luckies = [] 147 | 148 | for lucky in lucky_data_cards: 149 | if lucky['opened'] == 0: 150 | lucky_sum += lucky['lucky_coin'] 151 | 152 | to_upgrade = { 153 | 'id': lucky['lucky_task_id'], 154 | } 155 | 156 | luckies.append(to_upgrade) 157 | 158 | cards = self.get_cards() 159 | cards_sum = 0 160 | cards_to_upgrade = [] 161 | 162 | for card in cards: 163 | for lucky in luckies: 164 | if card['id'] == lucky['id']: 165 | cards_sum += card['upgrade_cost'] 166 | 167 | cards_to_upgrade.append(card) 168 | break 169 | 170 | if lucky_sum > cards_sum: 171 | self.upgrade_cards_by_id(cards_to_upgrade) 172 | 173 | def upgrade_cards_by_id(self, to_upgrade): 174 | for card in to_upgrade: 175 | self.get_balance(False) 176 | 177 | if self.balance >= card['upgrade_cost']: 178 | self.post(URL_CARDS_UPGRADE, {'taskId': card['id'], '_token': self.token}) 179 | self.log(MSG_CARD_UPGRADED_COMBO.format(card['name'])) 180 | 181 | def daily_bonus(self): 182 | data = { 183 | 'type': 1, 184 | '_token': self.token 185 | } 186 | 187 | response = self.post(URL_DAILY, data=data) 188 | daily_login_json = response.json() 189 | for i, step in enumerate(daily_login_json['data']['steps']): 190 | if step['today'] and not step['claimed']: 191 | self.post(URL_DAILY_COMPLETE, data) 192 | 193 | self.log(MSG_LOGIN_BONUS_COMPLETE.format(step=i)) 194 | break 195 | 196 | def get_hour_earnings(self, log=False): 197 | response = self.post(URL_USER_INFO, {'_token': self.token}) 198 | data = response.json()['data'] 199 | self.hours_earnings = data['hour_earnings'] 200 | 201 | if log: 202 | self.log(MSG_HOUR_EARNINGS.format(earnings=self.hours_earnings)) 203 | 204 | def get_balance(self, log=False): 205 | response = self.post(URL_USER_INFO, {'_token': self.token}) 206 | data = response.json()['data'] 207 | self.balance = data['balance'] 208 | 209 | if log: 210 | self.log(MSG_CURRENT_BALANCE.format(balance=self.balance)) 211 | 212 | def sync(self): 213 | return self.post(URL_REFRESH, {'_token': self.token}) 214 | 215 | def refresh_token(self): 216 | self.initiator.connect() 217 | self.authenticate() 218 | self.initiator.disconnect() 219 | 220 | def complete_tasks(self): 221 | response = self.post(URL_GET_TASKS, {'adv': 0, '_token': self.token}) 222 | tasks = response.json()['data'] 223 | 224 | for task in tasks: 225 | if task['completed'] == 0 and task['verifiable'] == 0: 226 | sleep(1) 227 | 228 | self.post(URL_COMPLETE_TASK, {'adv': 0, 'taskId': task['id'], '_token': self.token}) 229 | self.log(MSG_TASK_COMPLETED.format(name=task['title'])) 230 | 231 | def farm(self): 232 | self.sync() 233 | self.get_balance(True) 234 | self.get_hour_earnings(True) 235 | self.daily_bonus() 236 | self.get_bounty() 237 | self.complete_tasks() 238 | self.upgrade_cards() 239 | self.get_hour_earnings(True) 240 | -------------------------------------------------------------------------------- /bots/tapcoins/config.py: -------------------------------------------------------------------------------- 1 | BUY_UPGRADES = True # Покупать ли апгрейды 2 | UPGRADES_COUNT = 50 # Количество апгрейдов за раз, если 0 - то покупаем на весь баланс 3 | -------------------------------------------------------------------------------- /bots/tapcoins/strings.py: -------------------------------------------------------------------------------- 1 | URL_INIT = 'https://xapi.tapcoins.app/system/init' 2 | URL_LOGIN = 'https://xapi.tapcoins.app/auth/login' 3 | URL_COLLECT = 'https://xapi.tapcoins.app/coin/collect' 4 | URL_DAILY = 'https://xapi.tapcoins.app/daily/steps' 5 | URL_DAILY_COMPLETE = 'https://xapi.tapcoins.app/daily/complete' 6 | URL_CARDS_LIST = 'https://xapi.tapcoins.app/mine/task/list' 7 | URL_CARDS_CATEGORIES = 'https://xapi.tapcoins.app/mine/category/list' 8 | URL_CARDS_UPGRADE = 'https://xapi.tapcoins.app/mine/upgrade' 9 | URL_LUCKY_BOUNTY = 'https://xapi.tapcoins.app/mine/lucky' 10 | URL_USER_INFO = 'https://xapi.tapcoins.app/mine/mine' 11 | URL_REFRESH = 'https://xapi.tapcoins.app/user/online/refresh' 12 | URL_GET_TASKS = 'https://xapi.tapcoins.app/task/list' 13 | URL_COMPLETE_TASK = 'https://xapi.tapcoins.app/task/complete' 14 | 15 | HEADERS = { 16 | 'Accept': 'application/json, text/plain, */*', 17 | 'Accept-Encoding': 'gzip, deflate, br, zstd', 18 | 'Accept-Language': 'en-US,en;q=0.9', 19 | 'Content-Length': '53', 20 | 'Content-Type': 'application/x-www-form-urlencoded', 21 | 'Origin': 'https://game.tapcoins.app', 22 | 'Priority': 'u=1, i', 23 | 'Referer': 'https://game.tapcoins.app/', 24 | 'Sec-Ch-Ua': 'Chromium";v="122", "Not(A:Brand";v="24", "Android WebView";v="122', 25 | 'Sec-Ch-Ua-Mobile': '?1', 26 | 'Sec-Ch-Ua-Platform': '"Android"', 27 | 'Sec-Fetch-Dest': 'empty', 28 | 'Sec-Fetch-Mode': 'cors', 29 | 'Sec-Fetch-Site': 'same-site', 30 | 'User-Agent': 'Mozilla/5.0 (Linux; Android 11; Redmi 5 Plus Build/RQ3A.210805.001.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.64 Mobile Safari/537.36' 31 | } 32 | 33 | MSG_STARTING_UPDATING_CARDS = 'Начало прокачивания карточек' 34 | MSG_UPGRADING_CARDS = 'Прокачивание карточек' 35 | MSG_UPGRADE_COMPLETE = 'Прокачка карточек завершена' 36 | MSG_NO_CARDS_TO_UPGRADE = "Не найдены карты для прокачки" 37 | MSG_CARD_UPGRADED = "Прокачана карта {name} до уровня {level} за {cost} монет" 38 | MSG_NOT_ENOUGH_COINS = "Не хватает монет для прокачки" 39 | MSG_CARD_UPGRADED_COMBO = "Прокачана карта для комбо {}" 40 | MSG_LOGIN_BONUS_COMPLETE = "Бонус за вход {step} получен" 41 | MSG_MAX_UPGRADES_REACHED = "Достигнут лимит прокачки {limit}" 42 | MSG_CURRENT_BALANCE = "Текущий баланс: {balance}" 43 | MSG_HOUR_EARNINGS = "Прибыль в час: {earnings}" 44 | MSG_TASK_COMPLETED = "Задание {name} выполнено" 45 | -------------------------------------------------------------------------------- /bots/template/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /bots/template/client.py: -------------------------------------------------------------------------------- 1 | from bots.base.base import BaseFarmer 2 | from bots.template.strings import HEADERS 3 | 4 | 5 | class BotFarmer(BaseFarmer): 6 | name = "bot_username" 7 | extra_code = "ref_code" # в случае если рефка вида https://t.me/bot_username?start=ref_code 8 | app_extra = "ref_code" # в случае если рефка вида https://t.me/bot_username?action?param=ref_code (Это нужно доработать, но примеры есть среди ботов) 9 | initialization_data = {} # данные для передачи в инициатор, отличаются в зависимости от типа кнопки входа в бота 10 | refreshable_token = False # обновлять ли токен в боте 11 | codes_to_refresh = (401,) # при получении этих статусов будет автоматически обновляться токен вызовом self.refresh_token() 12 | 13 | 14 | def set_headers(self, *args, **kwargs): 15 | """ Установка заголовков """ 16 | self.headers = HEADERS.copy() 17 | 18 | def authenticate(self, *args, **kwargs): 19 | """ Аутентифифкация, получения токена, выставление заголовков, заполнение шаблона запроса и тд... """ 20 | raise NotImplementedError 21 | 22 | def refresh_token(self): 23 | """ Метод вызывается для обновления токена, при условии что self.refreshable_token == True """ 24 | raise NotImplementedError 25 | 26 | def set_start_time(self): 27 | """ 28 | Метод выставляет время следующего захода фармера. 29 | Например время когда закончится фарминг или накопятся тапы 30 | Время выставляется в формате timestamp 31 | time.time() + 60 это запуск через минуту 32 | """ 33 | raise NotImplementedError 34 | 35 | def farm(self): 36 | """ 37 | Основной метод, описывающий логику модуля. 38 | Покупки, прокачки. Все здесь 39 | """ 40 | raise NotImplementedError 41 | -------------------------------------------------------------------------------- /bots/template/strings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Модуль с текстовой информацие, которая задействуется в боте. 3 | - Эндпоинты 4 | - Шаблоны сообщений 5 | - Заголовки 6 | - Что-то еще, что может пригодиться. Различный хардкод... 7 | """ 8 | 9 | 10 | URL_INIT = "https://totalawesome.tg/init/" 11 | URL_BALANCE = "https://totalawesome.tg/balance/" 12 | 13 | MSG_PROFILE = "Обновил профиль" 14 | MSG_CLAIM = "Собрал нафармленное" 15 | 16 | HEADERS = {} 17 | -------------------------------------------------------------------------------- /bots/timeton/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TotalAwesome/BotFarmFactory/a014a70f66abbe1a46c9796847cd8813764978d1/bots/timeton/__init__.py -------------------------------------------------------------------------------- /bots/timeton/client.py: -------------------------------------------------------------------------------- 1 | from bots.base.utils import to_localtz_timestamp 2 | from bots.base.base import BaseFarmer, time 3 | from bots.timeton.strings import HEADERS, URL_AUTH, URL_INIT, URL_BONUS_CLAIM, URL_FARM_CLAIM, URL_FARM_START, \ 4 | MSG_BONUS, MSG_CLAIM, MSG_STATE, MSG_FARM, URL_STAKING_CLAIM, URL_FRIENDS_CLAIM, MSG_FRIENDS_CLAIM, \ 5 | MSG_STAKING_CLAIM 6 | 7 | class BotFarmer(BaseFarmer): 8 | 9 | name = 'timetonbot' 10 | info = {} 11 | extra_code = "TotalAwesome" 12 | initialization_data = dict(peer=name, bot=name, url=URL_INIT) 13 | payload_base = {} 14 | 15 | def set_headers(self, *args, **kwargs): 16 | self.headers = HEADERS.copy() 17 | 18 | def authenticate(self, *args, **kwargs): 19 | auth_data = self.initiator.get_auth_data(**self.initialization_data)['authData'] 20 | self.payload_base = {"telegramData": auth_data} 21 | self.info = self.api_call(URL_AUTH, json=self.payload_base)['data']['user'] 22 | 23 | def api_call(self, url, post=True, json=None): 24 | if post: 25 | response = self.post(url, json=json) 26 | else: 27 | response = self.get(url) 28 | if response.status_code == 200: 29 | return response.json() 30 | else: 31 | return {} 32 | 33 | def set_start_time(self): 34 | self.start_time = min(self.claim_time, self.ref_claim_time, self.staking_claim_time) 35 | 36 | @property 37 | def claim_time(self): 38 | return to_localtz_timestamp(self.info["claimDate"]) 39 | 40 | @property 41 | def ref_claim_time(self): 42 | return to_localtz_timestamp(self.info["refClaimTime"]) 43 | 44 | @property 45 | def staking_claim_time(self): 46 | return to_localtz_timestamp(self.info["stakingDate"]) 47 | 48 | @property 49 | def bonus_claim_time(self): 50 | return to_localtz_timestamp(self.info["counterDateBonus"]) 51 | 52 | def farm_claim(self): 53 | if self.info['claimActive'] and self.claim_time <= time(): 54 | if response := self.api_call(URL_FARM_CLAIM, post=False): 55 | self.info = response['data'] 56 | self.log(MSG_CLAIM) 57 | 58 | def ref_claim(self): 59 | if self.ref_claim_time <= time(): 60 | if response := self.api_call(URL_FRIENDS_CLAIM, post=False): 61 | self.info = response["data"] 62 | self.log(MSG_FRIENDS_CLAIM) 63 | 64 | def staking_claim(self): 65 | if self.staking_claim_time <= time(): 66 | if response := self.api_call(URL_STAKING_CLAIM, post=False): 67 | self.info = response["data"] 68 | self.log(MSG_STAKING_CLAIM) 69 | 70 | def claim_bonus(self): 71 | if self.bonus_claim_time <= time(): 72 | if response := self.api_call(URL_BONUS_CLAIM, post=False): 73 | self.info = response["data"] 74 | self.log(MSG_BONUS) 75 | 76 | def start_farm(self): 77 | if not self.info['claimActive']: 78 | if response := self.api_call(URL_FARM_START, post=False): 79 | self.info = response['data'] 80 | self.log(MSG_FARM) 81 | 82 | 83 | def farm(self): 84 | self.claim_bonus() 85 | self.farm_claim() 86 | self.start_farm() 87 | self.ref_claim() 88 | self.staking_claim() 89 | self.log(MSG_STATE.format(balance=self.info['balance'])) 90 | 91 | -------------------------------------------------------------------------------- /bots/timeton/strings.py: -------------------------------------------------------------------------------- 1 | URL_INIT = "https://timeton.io/main" 2 | URL_AUTH = "https://timeton.io/api/auth" 3 | URL_FRIENDS = "https://timeton.io/api/friends" 4 | URL_FRIENDS_CLAIM = "https://timeton.io/api/friends/claim" 5 | URL_BONUS_CLAIM = "https://timeton.io/api/bonus/claim" 6 | URL_FARM_CLAIM = "https://timeton.io/api/farm/claim" 7 | URL_STAKING_CLAIM = "https://timeton.io/api/staking/claim" 8 | URL_FARM_START = "https://timeton.io/api/farm/activate" 9 | 10 | MSG_BONUS = "Собрал бонус" 11 | MSG_CLAIM = "Собрал нафармленное" 12 | MSG_FRIENDS_CLAIM = "Собрал нафармленное рефералами" 13 | MSG_STAKING_CLAIM = "Собрал за стейкинг" 14 | MSG_FARM = "Начал фармить" 15 | MSG_STATE = "Баланс: {balance}" 16 | 17 | HEADERS = { 18 | 'sec-ch-ua': 'Chromium";v="122", "Not(A:Brand";v="24", "Android WebView";v="122', 19 | 'sec-ch-ua-mobile': '?1', 20 | 'user-agent': 'Mozilla/5.0 (Linux; Android 11; Redmi 5 Plus Build/RQ3A.210805.001.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.64 Mobile Safari/537.36', 21 | 'sec-ch-ua-platform': 'Android', 22 | 'content-type': 'application/json', 23 | 'Accept': '*/*', 24 | 'Origin': 'https://timeton.io', 25 | 'X-Requested-With': 'org.telegram.messenger', 26 | 'Sec-Fetch-Site': 'cross-site', 27 | 'Sec-Fetch-Mode': 'cors', 28 | 'Sec-Fetch-Dest': 'empty', 29 | } 30 | -------------------------------------------------------------------------------- /bots/zavod/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TotalAwesome/BotFarmFactory/a014a70f66abbe1a46c9796847cd8813764978d1/bots/zavod/__init__.py -------------------------------------------------------------------------------- /bots/zavod/client.py: -------------------------------------------------------------------------------- 1 | from random import random 2 | from bots.base.utils import to_localtz_timestamp, api_response 3 | from bots.base.base import BaseFarmer, time 4 | from bots.zavod.strings import HEADERS, URL_INIT, URL_CALIM, URL_FARM, URL_PROFILE, MSG_CLAIM, MSG_PROFILE, MSG_STATE 5 | 6 | 7 | class BotFarmer(BaseFarmer): 8 | 9 | name = 'Mdaowalletbot' 10 | extra_code = "102796269" 11 | info = dict(profile={}, farming={}) 12 | initialization_data = dict(peer=name, bot=name, url=URL_INIT) 13 | payload_base = {} 14 | codes_to_refresh = (400,) 15 | refreshable_token = True 16 | 17 | def set_headers(self, *args, **kwargs): 18 | self.headers = HEADERS.copy() 19 | self.get = api_response(super().get) 20 | self.post = api_response(super().post) 21 | self.delete = api_response(super().delete) 22 | 23 | def authenticate(self, *args, **kwargs): 24 | auth_data = self.initiator.get_auth_data(**self.initialization_data)['authData'] 25 | self.headers['telegram-init-data'] = auth_data 26 | 27 | def refresh_token(self): 28 | self.initiator.connect() 29 | self.authenticate() 30 | self.initiator.disconnect() 31 | 32 | def set_start_time(self): 33 | self.start_time = self.claim_date + int(random() * 10) 34 | 35 | def update_profile(self): 36 | if result := self.get(URL_PROFILE): 37 | self.info['profile'] = result 38 | self.log(MSG_PROFILE) 39 | 40 | def update_farming(self): 41 | if result := self.get(URL_FARM): 42 | self.info['farming'] = result 43 | 44 | @property 45 | def claim_date(self): 46 | last_claim = to_localtz_timestamp(self.info['farming'].get('lastClaim')) 47 | next_claim = last_claim + self.info['farming'].get('claimInterval') / 1000 48 | return next_claim 49 | 50 | def claim(self): 51 | if time() >= self.claim_date: 52 | if result := self.post(URL_CALIM): 53 | self.info['profile'] = result 54 | self.log(MSG_CLAIM) 55 | 56 | def farm(self): 57 | self.update_profile() 58 | self.update_farming() 59 | self.claim() 60 | self.update_farming() 61 | self.log(MSG_STATE.format(balance=self.info['profile'].get('tokens'))) 62 | 63 | -------------------------------------------------------------------------------- /bots/zavod/strings.py: -------------------------------------------------------------------------------- 1 | URL_INIT = "https://zavod.mdaowallet.com/" 2 | URL_PROFILE = "https://zavod-api.mdaowallet.com/user/profile" # GET 3 | URL_FARM = "https://zavod-api.mdaowallet.com/user/farm" # POST 4 | URL_CALIM = "https://zavod-api.mdaowallet.com/user/claim" # GET 5 | 6 | 7 | MSG_PROFILE = "Обновил профиль" 8 | MSG_CLAIM = "Склеймил и начал фармить" 9 | MSG_STATE = "Баланс: {balance}" 10 | 11 | 12 | HEADERS = { 13 | 14 | 'authority': 'zavod-api.mdaowallet.com', 15 | 'accept': 'application/json, text/plain, */*', 16 | 'accept-language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7,cy;q=0.6', 17 | 'cache-control': 'no-cache', 18 | 'origin': 'https://zavod.mdaowallet.com', 19 | 'pragma': 'no-cache', 20 | 'referer': 'https://zavod.mdaowallet.com/', 21 | 'sec-ch-ua': '"Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"', 22 | 'sec-ch-ua-mobile': '?0', 23 | 'sec-ch-ua-platform': '"Linux"', 24 | 'sec-fetch-dest': 'empty', 25 | 'sec-fetch-mode': 'cors', 26 | 'sec-fetch-site': 'same-site', 27 | 'telegram-init-data': '', 28 | 'user-agent': '', 29 | } -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | ACCOUNTS_DIR = "accounts_data" 2 | # TELEGRAM WEB 3 | TELEGRAM_AUTH = dict( 4 | api_id=2496, 5 | api_hash="8da85b0d5bfe62527e5b244c209159c3", 6 | device_model="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36", 7 | system_version="Windows", 8 | app_version="1.57 Z", 9 | lang_code="en", 10 | system_lang_code="en-US", 11 | ) 12 | 13 | DEBUG = True 14 | RETRY_ATTEMPTS = 3 15 | 16 | ENABLED_BOTS = [ 17 | # Пустой список = все боты включены 18 | # иначе будут работать только те, что в этом списке 19 | ] 20 | 21 | DISABLED_BOTS = [ 22 | # Добавить боты, необходимые для исключения 23 | ] 24 | 25 | SLEEP_AT_NIGHT = False # При True ночью фарминг не производится 26 | NIGHT_HOURS = (0, 7) # Диапазон времени, когда у фермы тихий час 27 | MULTITHREAD = False # При True на каждый аккаунт будет отдельный поток 28 | 29 | try: 30 | from config_local import * 31 | except ImportError: 32 | pass 33 | -------------------------------------------------------------------------------- /factory.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://github.com/TotalAwesome/BotFarmFactory 3 | https://t.me/CryptoAutoFarm 4 | """ 5 | 6 | from time import sleep 7 | from random import random, shuffle 8 | 9 | from initiator import Initiator 10 | from accounts import TELEGRAM_ACCOUNTS 11 | from bots.base.base import logging 12 | from bots.base.utils import check_proxy 13 | from config import MULTITHREAD 14 | from utils import BOTS 15 | if MULTITHREAD: 16 | from threading import Thread 17 | 18 | 19 | def make_account_farmers(account): 20 | phone = account['phone'] 21 | if proxy := account.get('proxy'): 22 | proxies = dict(http=proxy, https=proxy) 23 | proxy = proxy if check_proxy(proxies=proxies) else None 24 | try: 25 | initiator = Initiator(phone) 26 | except Exception as e: 27 | logging.error(f'{phone} Error: {e}') 28 | return [] 29 | farmers = [] 30 | for farmer_class in BOTS: 31 | try: 32 | farmer = farmer_class(initiator=initiator, proxy=proxy) 33 | except Exception as e: 34 | logging.error(f'{farmer_class.name} init error: {e}') 35 | continue 36 | if not farmer.is_alive: 37 | continue 38 | farmers.append(farmer) 39 | initiator.disconnect() 40 | sleep(random() * 10) 41 | return farmers 42 | 43 | def main(farmers): 44 | while True: 45 | shuffle(farmers) 46 | for farmer in farmers: 47 | farmer.proceed_farming() 48 | sleep(1 + random()) 49 | sleep(1) 50 | 51 | def farm_in_thread(phone): 52 | import asyncio 53 | loop = asyncio.new_event_loop() 54 | asyncio.set_event_loop(loop) 55 | main(make_account_farmers(phone)) 56 | 57 | 58 | if MULTITHREAD: 59 | for account in TELEGRAM_ACCOUNTS: 60 | Thread(target=farm_in_thread, args=(account,)).start() 61 | while True: 62 | input() 63 | else: 64 | farmers = [] 65 | for account in TELEGRAM_ACCOUNTS: 66 | farmers += make_account_farmers(account) 67 | print('') 68 | farmer_names = ", ".join(set([farmer.name.lower() for farmer in farmers])) 69 | logging.info("Найдены фармеры: {farmer_names}".format(farmer_names=farmer_names)) 70 | 71 | if not farmers: 72 | exit() 73 | 74 | main(farmers) 75 | -------------------------------------------------------------------------------- /initiator.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | from time import sleep 4 | from telethon.sync import TelegramClient, functions, types 5 | from telethon.tl.functions.channels import JoinChannelRequest, InviteToChannelRequest 6 | from telethon.errors import FloodWaitError 7 | from urllib.parse import unquote, parse_qs, urlparse 8 | from datetime import timedelta 9 | from config import ACCOUNTS_DIR, TELEGRAM_AUTH 10 | from bots.base.base import logging 11 | 12 | 13 | def username(dialog): 14 | username = str(getattr(dialog.message.chat, 'username', '_')).lower() 15 | return username 16 | 17 | 18 | def catch_flood_error(func): 19 | def wrapper(*args, **kwargs): 20 | while True: 21 | try: 22 | return func(*args, **kwargs) 23 | except FloodWaitError as e: 24 | logging.INFO(f'Флудим, подождем {e.seconds} секунд') 25 | sleep(e.seconds) 26 | return wrapper 27 | 28 | 29 | class Initiator(TelegramClient): 30 | 31 | phone = None 32 | registered = [] 33 | dialogs = None 34 | 35 | def __init__(self, phone): 36 | kwargs = {} 37 | if phone: 38 | self.phone = phone 39 | if not os.path.exists(ACCOUNTS_DIR): 40 | os.mkdir(ACCOUNTS_DIR) 41 | filename = os.path.join(ACCOUNTS_DIR, phone.strip('+')) 42 | super().__init__(session=filename, **TELEGRAM_AUTH) 43 | self.start(phone=self.phone) 44 | else: 45 | raise Exception('Provide a phone number ({})'.format(str(kwargs))) 46 | 47 | @catch_flood_error 48 | def is_bot_registered(self, botname=None): 49 | if not botname: 50 | return 51 | botname = botname.lower() 52 | if botname not in self.registered: 53 | self.dialogs = self.dialogs or self.get_dialogs() 54 | is_registered = any(map(lambda x: username(x) == botname, self.dialogs)) 55 | if is_registered: 56 | self.registered.append(botname) 57 | return botname in self.registered 58 | 59 | @catch_flood_error 60 | def prepare_bot(self, *args): 61 | if self.is_bot_registered(args[0]): 62 | return 63 | request = functions.messages.StartBotRequest(*args) 64 | self(request) 65 | 66 | @catch_flood_error 67 | def get_auth_data(self, **kwargs): 68 | kwargs['platform'] = kwargs.get('platform', 'android') 69 | kwargs['from_bot_menu'] = kwargs.get('from_bot_menu', False) 70 | dicted = kwargs.pop('dicted', None) 71 | if not 'app' in kwargs: 72 | web_app = self(functions.messages.RequestWebViewRequest(**kwargs)) 73 | else: 74 | kwargs.pop('from_bot_menu') 75 | web_app = self(functions.messages.RequestAppWebViewRequest(**kwargs, write_allowed=True)) 76 | auth_data = web_app.url.split('#tgWebAppData=')[1].replace("%3D","=").split('&tgWebAppVersion=')[0].replace("%26","&") 77 | user = auth_data.split("user=")[1].split("&")[0] 78 | return {"userId": self._self_id, "authData": auth_data.replace(user, unquote(user)), 'url': web_app.url} 79 | 80 | @catch_flood_error 81 | def join_group(self, group_link): 82 | self(JoinChannelRequest(group_link)) 83 | 84 | @catch_flood_error 85 | def subscribe_channel(self, channel_link): 86 | self(JoinChannelRequest(channel_link)) 87 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | telethon 2 | requests 3 | brotli 4 | python-dateutil -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | from os import path, listdir 2 | from importlib import import_module 3 | from config import ENABLED_BOTS, DISABLED_BOTS 4 | from bots.base.base import logging 5 | 6 | 7 | def import_bots(): 8 | bots = [] 9 | if path.isdir("bots"): 10 | for directory in listdir("bots"): 11 | if directory == 'template': 12 | continue 13 | if ENABLED_BOTS and directory not in ENABLED_BOTS: 14 | continue 15 | if DISABLED_BOTS and directory in DISABLED_BOTS: 16 | continue 17 | try: 18 | module = import_module(f"bots.{directory}.client") 19 | bots.append(module.BotFarmer) 20 | except ImportError: 21 | pass 22 | except Exception as e: 23 | logging.error(e) 24 | else: 25 | raise Exception("No bots :(") 26 | return bots 27 | 28 | 29 | BOTS = import_bots() 30 | --------------------------------------------------------------------------------