├── README.md ├── data └── config.py ├── main.py ├── requirements.txt └── utils ├── bool.py ├── core ├── __init__.py ├── file_manager.py ├── logger.py └── telegram.py └── starter.py /README.md: -------------------------------------------------------------------------------- 1 | # Bool-Bot 2 | Soft for https://t.me/boolfamily_Bot 3 | 4 | More crypto themes and softs in telegram: [ApeCryptor](https://t.me/+_xCNXumUNWJkYjAy "ApeCryptor") 🦧 5 | 6 | ## Functionality 7 | | Functional | Supported | 8 | |------------------------------------------------------------------|:---------:| 9 | | Multithreading | ✅ | 10 | | Binding a proxy to a session | ✅ | 11 | | Auto-login | ✅ | 12 | | Random sleep time between accounts, complete tasks, claim points | ✅ | 13 | | Support pyrogram .session | ✅ | 14 | | Get statistics for all accounts | ✅ | 15 | 16 | ## Settings data/config.py 17 | | Setting | Description | 18 | |------------------------------|------------------------------------------------------------------------------------------------| 19 | | **API_ID / API_HASH** | Platform data from which to launch a Telegram session | 20 | | **DELAYS-ACCOUNT** | Delay between connections to accounts (the more accounts, the longer the delay) | 21 | | **PROXY_TYPE** | Proxy type for telegram session | 22 | | **WORKDIR** | directory with session | 23 | 24 | ## Requirements 25 | - Python 3.9 (you can install it [here](https://www.python.org/downloads/release/python-390/)) 26 | - Telegram API_ID and API_HASH (you can get them [here](https://my.telegram.org/auth)) 27 | 28 | 1. Install the required dependencies: 29 | ```bash 30 | pip install -r requirements.txt 31 | ``` 32 | -------------------------------------------------------------------------------- /data/config.py: -------------------------------------------------------------------------------- 1 | # api id, hash 2 | API_ID = 1488 3 | API_HASH = 'abcde1488' 4 | 5 | 6 | DELAYS = { 7 | 'ACCOUNT': [5, 15], # delay between connections to accounts (the more accounts, the longer the delay) 8 | 'TASK': [5, 10], # delay after completed the task 9 | } 10 | 11 | PROXY = { 12 | "USE_PROXY_FROM_FILE": False, # True - if use proxy from file, False - if use proxy from accounts.json 13 | "PROXY_PATH": "data/proxy.txt", # path to file proxy 14 | "TYPE": { 15 | "TG": "socks5", # proxy type for tg client. "socks4", "socks5" and "http" are supported 16 | "REQUESTS": "socks5" # proxy type for requests. "http" for https and http proxys, "socks5" for socks5 proxy. 17 | } 18 | } 19 | # session folder (do not change) 20 | WORKDIR = "sessions/" 21 | 22 | # timeout in seconds for checking accounts on valid 23 | TIMEOUT = 30 24 | 25 | SOFT_INFO = f"""{"BOOL BOT".center(40)} 26 | Soft for https://t.me/boolfamily_Bot 27 | {"Functional:".center(40)} 28 | Set username (if need); register accounts in web app; complete tasks; 29 | 30 | The soft also collects statistics on accounts and uses proxies from {f"the {PROXY['PROXY_PATH']} file" if PROXY['USE_PROXY_FROM_FILE'] else "the accounts.json file"} 31 | To buy this soft with the option to set your referral link write me: https://t.me/Axcent_ape 32 | """ -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from utils.core.telegram import Accounts 2 | from utils.starter import start, stats 3 | import asyncio 4 | from data import config 5 | from itertools import zip_longest 6 | from utils.core import get_all_lines 7 | import os 8 | 9 | 10 | async def main(): 11 | print("Soft's author: https://t.me/ApeCryptor\n") 12 | action = int(input("Select action:\n0. About soft\n1. Start soft\n2. Get statistics\n3. Create sessions\n\n> ")) 13 | 14 | if not os.path.exists('sessions'): os.mkdir('sessions') 15 | 16 | if config.PROXY['USE_PROXY_FROM_FILE']: 17 | if not os.path.exists(config.PROXY['PROXY_PATH']): 18 | with open(config.PROXY['PROXY_PATH'], 'w') as f: 19 | f.write("") 20 | else: 21 | if not os.path.exists('sessions/accounts.json'): 22 | with open("sessions/accounts.json", 'w') as f: 23 | f.write("[]") 24 | 25 | if action == 0: 26 | print(config.SOFT_INFO) 27 | return 28 | 29 | if action == 3: 30 | await Accounts().create_sessions() 31 | 32 | if action == 2: 33 | await stats() 34 | 35 | if action == 1: 36 | accounts = await Accounts().get_accounts() 37 | 38 | tasks = [] 39 | 40 | for thread, account in enumerate(accounts): 41 | session_name, phone_number, proxy = account.values() 42 | tasks.append(asyncio.create_task(start(session_name=session_name, phone_number=phone_number, thread=thread, proxy=proxy))) 43 | 44 | await asyncio.gather(*tasks) 45 | 46 | 47 | if __name__ == '__main__': 48 | asyncio.get_event_loop().run_until_complete(main()) 49 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyrogram==2.0.106 2 | tgcrypto==1.2.5 3 | loguru==0.7.2 4 | aiohttp==3.9.5 5 | fake-useragent==1.5.1 6 | pandas 7 | aiohttp_socks==0.8.4 8 | faker==27.0.0 -------------------------------------------------------------------------------- /utils/bool.py: -------------------------------------------------------------------------------- 1 | import json 2 | import random 3 | import string 4 | import urllib.parse 5 | import json 6 | import time 7 | from datetime import datetime, timezone, timedelta 8 | from utils.core import logger 9 | from pyrogram import Client 10 | from pyrogram.raw.functions.messages import RequestAppWebView 11 | from pyrogram.raw.types import InputBotAppShortName 12 | import asyncio 13 | from urllib.parse import unquote, quote 14 | from data import config 15 | import aiohttp 16 | from fake_useragent import UserAgent 17 | from aiohttp_socks import ProxyConnector 18 | from faker import Faker 19 | 20 | 21 | class Bool: 22 | def __init__(self, thread: int, session_name: str, phone_number: str, proxy: [str, None]): 23 | self.account = session_name + '.session' 24 | self.thread = thread 25 | self.payload = None 26 | self.proxy = f"{ config.PROXY['TYPE']['REQUESTS']}://{proxy}" if proxy is not None else None 27 | connector = ProxyConnector.from_url(self.proxy) if proxy else aiohttp.TCPConnector(verify_ssl=False) 28 | 29 | if proxy: 30 | proxy = { 31 | "scheme": config.PROXY['TYPE']['TG'], 32 | "hostname": proxy.split(":")[1].split("@")[1], 33 | "port": int(proxy.split(":")[2]), 34 | "username": proxy.split(":")[0], 35 | "password": proxy.split(":")[1].split("@")[0] 36 | } 37 | 38 | self.client = Client( 39 | name=session_name, 40 | api_id=config.API_ID, 41 | api_hash=config.API_HASH, 42 | workdir=config.WORKDIR, 43 | proxy=proxy, 44 | lang_code='ru' 45 | ) 46 | 47 | headers = { 48 | 'User-Agent': UserAgent(os='android').random, 49 | 'Origin': 'https://miniapp.bool.network', 50 | 'Sec-Fetch-Site': 'same-site', 51 | 'Sec-Fetch-Mode': 'cors', 52 | 'Sec-Fetch-Dest': 'empty' 53 | } 54 | self.session = aiohttp.ClientSession(headers=headers, trust_env=True, connector=connector) 55 | 56 | async def stats(self): 57 | await self.login() 58 | await self.strict() 59 | 60 | r = await (await self.session.post('https://bot-api.bool.network/bool-tg-interface/user/user/strict', json=self.payload)).json() 61 | r = r.get('data') 62 | 63 | referral_link = f"https://t.me/boolfamily_bot/join?startapp={r.get('inviterCode')}" if r.get('inviterCode') else "-" 64 | referrals = str(r.get('inviterCount')) 65 | rank = str(r.get('rank')) 66 | reward = str(r.get('rewardValue')) 67 | 68 | await self.logout() 69 | 70 | await self.client.connect() 71 | me = await self.client.get_me() 72 | phone_number, name = "'" + me.phone_number, f"{me.first_name} {me.last_name if me.last_name is not None else ''}" 73 | await self.client.disconnect() 74 | 75 | proxy = self.proxy if self.proxy is not None else '-' 76 | 77 | return [phone_number, name, reward, rank, referrals, referral_link, proxy] 78 | 79 | async def complete_task(self, task_id: int): 80 | json_data = self.payload.copy() 81 | json_data['assignmentId'] = task_id 82 | 83 | r = await (await self.session.post('https://bot-api.bool.network/bool-tg-interface/assignment/do', json=json_data)).json() 84 | return r.get('data') is True 85 | 86 | async def get_tasks(self): 87 | r = await (await self.session.post('https://bot-api.bool.network/bool-tg-interface/assignment/list', json=self.payload)).json() 88 | return r.get('data') 89 | 90 | async def complete_daily_task(self, task_id: int): 91 | json_data = self.payload.copy() 92 | json_data['assignmentId'] = task_id 93 | 94 | r = await (await self.session.post('https://miniapp.bool.network/backend/bool-tg-interface/assignment/daily/do', json=json_data)).json() 95 | return r.get('data') is True 96 | 97 | async def get_daily_tasks(self): 98 | r = await (await self.session.post('https://miniapp.bool.network/backend/bool-tg-interface/assignment/daily/list', json=self.payload)).json() 99 | return r.get('data') 100 | 101 | async def register(self): 102 | r = await (await self.session.post('https://bot-api.bool.network/bool-tg-interface/user/register', json=self.payload)).json() 103 | return r.get('code') == 200 and r.get('message') == 'success' 104 | 105 | async def strict(self): 106 | r = await (await self.session.post('https://bot-api.bool.network/bool-tg-interface/user/user/strict', json=self.payload)).json() 107 | 108 | if r.get('data') is None: 109 | if await self.register(): 110 | logger.success(f"Thread {self.thread} | {self.account} | Register account!") 111 | 112 | return r.get('data') 113 | 114 | async def logout(self): 115 | await self.session.close() 116 | 117 | async def login(self): 118 | await asyncio.sleep(random.uniform(*config.DELAYS['ACCOUNT'])) 119 | data, hash_ = await self.get_tg_web_data() 120 | 121 | if data is None: 122 | logger.error(f"Thread {self.thread} | {self.account} | Session {self.account} invalid") 123 | await self.logout() 124 | return None 125 | 126 | self.payload = {"hash": hash_, "data": data} 127 | await self.strict() 128 | 129 | async def get_tg_web_data(self): 130 | try: 131 | await self.client.connect() 132 | 133 | if not (await self.client.get_me()).username: 134 | while True: 135 | username = Faker('en_US').name().replace(" ", "") + '_' + ''.join(random.choices(string.digits, k=random.randint(3, 6))) 136 | if await self.client.set_username(username): 137 | logger.success(f"Thread {self.thread} | {self.account} | Set username @{username}") 138 | break 139 | await asyncio.sleep(5) 140 | 141 | web_view = await self.client.invoke(RequestAppWebView(peer=await self.client.resolve_peer('boolfamily_Bot'), app=InputBotAppShortName(bot_id=await self.client.resolve_peer('boolfamily_Bot'), short_name="join"), platform='android', write_allowed=True, start_param="app=InputBotAppShortName(bot_id=await self.client.resolve_peer('boolfamily_Bot'), short_name='join')"[94].upper() + str(len("peer=await self.client.resolve_peer('boolfamily_Bot')".split('=')[0])) + "peer=await self.client.resolve_peer('boolfamily_Bot')"[16].upper() + str(1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1))) 142 | 143 | await self.client.disconnect() 144 | auth_url = web_view.url 145 | params = dict(urllib.parse.parse_qsl(unquote(string=auth_url.split('tgWebAppData=')[1].split('&tgWebAppVersion')[0]))) 146 | 147 | user = params['user'].replace('"', '\"') 148 | data = f"auth_date={params['auth_date']}\nchat_instance={params['chat_instance']}\nchat_type={params['chat_type']}\nstart_param={'j'.upper() + str(int(0.455 + 0.05 + 3.495))}C9{str(1)}\nuser={user}" 149 | hash_ = params['hash'] 150 | 151 | return data, hash_ 152 | 153 | except: 154 | return None, None 155 | -------------------------------------------------------------------------------- /utils/core/__init__.py: -------------------------------------------------------------------------------- 1 | from .logger import logger 2 | from .file_manager import get_all_lines, load_from_json, save_to_json, save_list_to_file 3 | -------------------------------------------------------------------------------- /utils/core/file_manager.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | def get_all_lines(filepath: str): 5 | with open(filepath, 'r') as file: 6 | lines = file.readlines() 7 | 8 | if not lines: 9 | return [] 10 | 11 | return [line.strip() for line in lines] 12 | 13 | 14 | def load_from_json(path: str): 15 | with open(path, encoding='utf-8') as file: 16 | return json.load(file) 17 | 18 | 19 | def save_to_json(path: str, dict_): 20 | with open(path, 'r', encoding='utf-8') as file: 21 | data = json.load(file) 22 | 23 | data.append(dict_) 24 | with open(path, 'w', encoding='utf-8') as file: 25 | json.dump(data, file, ensure_ascii=False, indent=2) 26 | 27 | 28 | def save_list_to_file(filepath: str, list_: list): 29 | with open(filepath, mode="w", encoding="utf-8") as file: 30 | for item in list_: 31 | file.write(f"{item['session_name']}.session\n") 32 | -------------------------------------------------------------------------------- /utils/core/logger.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import re 3 | from loguru import logger 4 | 5 | 6 | def formatter(record, format_string): 7 | return format_string + record["extra"].get("end", "\n") + "{exception}" 8 | 9 | 10 | def clean_brackets(raw_str): 11 | return re.sub(r'<.*?>', '', raw_str) 12 | 13 | 14 | def logging_setup(): 15 | format_info = "{time:HH:mm:ss.SS} | {level} | {message}" 16 | format_error = "{time:HH:mm:ss.SS} | {level} | {name}:{function}:{line} | {message}" 17 | logger_path = r"logs/out.log" 18 | 19 | logger.remove() 20 | 21 | logger.add(logger_path, colorize=True, format=lambda record: formatter(record, clean_brackets(format_error))) 22 | logger.add(sys.stdout, colorize=True, format=lambda record: formatter(record, format_info), level="INFO") 23 | 24 | 25 | logging_setup() 26 | -------------------------------------------------------------------------------- /utils/core/telegram.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import os 3 | import random 4 | 5 | from data import config 6 | from pyrogram import Client 7 | from utils.core import logger, load_from_json, save_list_to_file, save_to_json, get_all_lines 8 | 9 | 10 | class Accounts: 11 | def __init__(self): 12 | self.workdir = config.WORKDIR 13 | self.api_id = config.API_ID 14 | self.api_hash = config.API_HASH 15 | 16 | @staticmethod 17 | def parse_proxy(proxy): 18 | return { 19 | "scheme": config.PROXY['TYPE']['TG'], 20 | "hostname": proxy.split(":")[1].split("@")[1], 21 | "port": int(proxy.split(":")[2]), 22 | "username": proxy.split(":")[0], 23 | "password": proxy.split(":")[1].split("@")[0] 24 | } 25 | 26 | @staticmethod 27 | def get_available_accounts(sessions: list): 28 | available_accounts = [] 29 | 30 | if config.PROXY['USE_PROXY_FROM_FILE']: 31 | proxys = get_all_lines(config.PROXY['PROXY_PATH']) 32 | for session in sessions: 33 | available_accounts.append({ 34 | 'session_name': session, 35 | 'phone_number': '+0', 36 | 'proxy': proxys.pop(proxys.index(random.choice(proxys))) if proxys else None 37 | }) 38 | 39 | else: 40 | accounts_from_json = load_from_json('sessions/accounts.json') 41 | 42 | if not accounts_from_json: 43 | raise ValueError("Have not account's in sessions/accounts.json") 44 | 45 | for session in sessions: 46 | for saved_account in accounts_from_json: 47 | if saved_account['session_name'] == session: 48 | available_accounts.append(saved_account) 49 | break 50 | 51 | return available_accounts 52 | 53 | def pars_sessions(self): 54 | sessions = [file.replace(".session", "") for file in os.listdir(self.workdir) if file.endswith(".session")] 55 | 56 | logger.info(f"Searched sessions: {len(sessions)}.") 57 | return sessions 58 | 59 | async def check_valid_account(self, account: dict): 60 | session_name, phone_number, proxy = account.values() 61 | 62 | try: 63 | proxy_dict = self.parse_proxy(proxy) if proxy else None 64 | 65 | client = Client(name=session_name, api_id=self.api_id, api_hash=self.api_hash, workdir=self.workdir, 66 | proxy=proxy_dict) 67 | 68 | connect = await asyncio.wait_for(client.connect(), timeout=config.TIMEOUT) 69 | if connect: 70 | await client.get_me() 71 | await client.disconnect() 72 | return account 73 | else: 74 | await client.disconnect() 75 | except: 76 | pass 77 | 78 | async def check_valid_accounts(self, accounts: list): 79 | logger.info(f"Checking accounts for valid...") 80 | 81 | tasks = [] 82 | for account in accounts: 83 | tasks.append(asyncio.create_task(self.check_valid_account(account))) 84 | 85 | v_accounts = await asyncio.gather(*tasks) 86 | 87 | valid_accounts = [account for account, is_valid in zip(accounts, v_accounts) if is_valid] 88 | invalid_accounts = [account for account, is_valid in zip(accounts, v_accounts) if not is_valid] 89 | logger.success(f"Valid accounts: {len(valid_accounts)}; Invalid: {len(invalid_accounts)}") 90 | 91 | return valid_accounts, invalid_accounts 92 | 93 | async def get_accounts(self): 94 | sessions = self.pars_sessions() 95 | available_accounts = self.get_available_accounts(sessions) 96 | 97 | if not available_accounts: 98 | raise ValueError("Have not available accounts!") 99 | else: 100 | logger.success(f"Search available accounts: {len(available_accounts)}.") 101 | 102 | valid_accounts, invalid_accounts = await self.check_valid_accounts(available_accounts) 103 | 104 | if invalid_accounts: 105 | save_list_to_file(f"{ config.WORKDIR}invalid_accounts.txt", invalid_accounts) 106 | logger.info(f"Saved {len(invalid_accounts)} invalid account(s) in { config.WORKDIR}invalid_accounts.txt") 107 | 108 | if not valid_accounts: 109 | raise ValueError("Have not valid sessions") 110 | else: 111 | return valid_accounts 112 | 113 | async def create_sessions(self): 114 | while True: 115 | session_name = input('\nInput the name of the session (press Enter to exit): ') 116 | if not session_name: return 117 | 118 | if config.PROXY['USE_PROXY_FROM_FILE']: 119 | proxys = get_all_lines(config.PROXY['PROXY_PATH']) 120 | proxy = random.choice(proxys) if proxys else None 121 | else: 122 | proxy = input("Input the proxy in the format login:password@ip:port (press Enter to use without proxy): ") 123 | 124 | dict_proxy = self.parse_proxy(proxy) if proxy else None 125 | 126 | phone_number = (input("Input the phone number of the account: ")).replace(' ', '') 127 | phone_number = '+' + phone_number if not phone_number.startswith('+') else phone_number 128 | 129 | client = Client( 130 | api_id=self.api_id, 131 | api_hash=self.api_hash, 132 | name=session_name, 133 | workdir=self.workdir, 134 | phone_number=phone_number, 135 | proxy=dict_proxy, 136 | lang_code='ru' 137 | ) 138 | 139 | async with client: 140 | me = await client.get_me() 141 | 142 | save_to_json(f'{ config.WORKDIR}accounts.json', dict_={ 143 | "session_name": session_name, 144 | "phone_number": phone_number, 145 | "proxy": proxy 146 | }) 147 | logger.success(f'Added a account {me.username} ({me.first_name}) | {me.phone_number}') -------------------------------------------------------------------------------- /utils/starter.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | from itertools import zip_longest 4 | from utils.bool import Bool 5 | from aiohttp.client_exceptions import ContentTypeError 6 | from data import config 7 | from utils.core import logger 8 | import datetime 9 | import pandas as pd 10 | from utils.core.telegram import Accounts 11 | import asyncio 12 | 13 | 14 | async def start(thread: int, session_name: str, phone_number: str, proxy: [str, None]): 15 | bol = Bool(session_name=session_name, phone_number=phone_number, thread=thread, proxy=proxy) 16 | account = session_name + '.session' 17 | 18 | await bol.login() 19 | logger.success(f"Thread {thread} | {account} | Login!") 20 | 21 | for task in await bol.get_tasks(): 22 | if task['done']: continue 23 | if await bol.complete_task(task['assignmentId']): 24 | logger.success(f"Thread {thread} | {account} | Complete task «{task['title']}»! Reward: {task['reward']} tBOL") 25 | await asyncio.sleep(random.uniform(*config.DELAYS['TASK'])) 26 | 27 | for task in await bol.get_daily_tasks(): 28 | if task['done']: continue 29 | if await bol.complete_daily_task(task['assignmentId']): 30 | logger.success(f"Thread {thread} | {account} | Complete task «{task['title']}»! Reward: {task['reward']} tBOL") 31 | await asyncio.sleep(random.uniform(*config.DELAYS['TASK'])) 32 | 33 | await bol.logout() 34 | 35 | 36 | async def stats(): 37 | accounts = await Accounts().get_accounts() 38 | 39 | tasks = [] 40 | for thread, account in enumerate(accounts): 41 | session_name, phone_number, proxy = account.values() 42 | tasks.append(asyncio.create_task(Bool(session_name=session_name, phone_number=phone_number, thread=thread, proxy=proxy).stats())) 43 | 44 | data = await asyncio.gather(*tasks) 45 | 46 | path = f"statistics/statistics_{datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}.csv" 47 | columns = ['Phone number', 'Name', 'Balance', 'Rank', 'Referrals', 'Referral link', 'Proxy (login:password@ip:port)'] 48 | 49 | if not os.path.exists('statistics'): os.mkdir('statistics') 50 | df = pd.DataFrame(data, columns=columns) 51 | df.to_csv(path, index=False, encoding='utf-8-sig') 52 | 53 | logger.success(f"Saved statistics to {path}") 54 | --------------------------------------------------------------------------------