├── bot ├── core │ ├── __init__.py │ ├── headers.py │ ├── registrator.py │ ├── agents.py │ └── tapper.py ├── plugins │ ├── __init__.py │ └── manager.py ├── __init__.py ├── config │ ├── __init__.py │ ├── proxies.txt │ └── config.py ├── exceptions │ └── __init__.py └── utils │ ├── __init__.py │ ├── logger.py │ ├── scripts.py │ ├── launcher.py │ └── emojis.py ├── requirements.txt ├── .github └── images │ └── demo.png ├── START.bat ├── .env-example ├── docker-compose.yml ├── main.py ├── Dockerfile ├── INSTALL.bat ├── run.sh ├── install.sh ├── README-EN.md └── README.md /bot/core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bot/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bot/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '1.1' 2 | -------------------------------------------------------------------------------- /bot/config/__init__.py: -------------------------------------------------------------------------------- 1 | from .config import settings 2 | -------------------------------------------------------------------------------- /bot/exceptions/__init__.py: -------------------------------------------------------------------------------- 1 | class InvalidSession(BaseException): 2 | ... 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DARKM00N1337/ShitCoinTapBot/HEAD/requirements.txt -------------------------------------------------------------------------------- /.github/images/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DARKM00N1337/ShitCoinTapBot/HEAD/.github/images/demo.png -------------------------------------------------------------------------------- /bot/config/proxies.txt: -------------------------------------------------------------------------------- 1 | type://user:pass@ip:port 2 | type://user:pass:ip:port 3 | type://ip:port:user:pass 4 | type://ip:port@user:pass 5 | type://ip:port -------------------------------------------------------------------------------- /START.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Activating virtual environment... 3 | call venv\Scripts\activate 4 | echo Starting the bot... 5 | python main.py 6 | pause 7 | -------------------------------------------------------------------------------- /.env-example: -------------------------------------------------------------------------------- 1 | API_ID= 2 | API_HASH= 3 | 4 | SLEEP_BETWEEN_TAP= 5 | CLICKS_FOR_SLEEP= 6 | LONG_SLEEP_BETWEEN_TAP= 7 | SLEEP_BY_MIN_ENERGY_IN_RANGE= 8 | SHOW_BALANCE_EVERY_TAPS= 9 | 10 | USE_PROXY_FROM_FILE= -------------------------------------------------------------------------------- /bot/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .logger import logger 2 | from . import launcher 3 | from . import scripts 4 | from . import emojis 5 | 6 | 7 | import os 8 | 9 | if not os.path.exists(path="sessions"): 10 | os.mkdir(path="sessions") 11 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | bot: 4 | container_name: 'ShitCoinTapBot' 5 | build: 6 | context: . 7 | stop_signal: SIGINT 8 | restart: unless-stopped 9 | command: "python3 main.py -a 2" 10 | volumes: 11 | - .:/app -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from contextlib import suppress 3 | 4 | from bot.utils.launcher import process 5 | 6 | 7 | async def main(): 8 | await process() 9 | 10 | 11 | if __name__ == '__main__': 12 | with suppress(KeyboardInterrupt): 13 | asyncio.run(main()) 14 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10.11-alpine3.18 2 | 3 | WORKDIR app/ 4 | 5 | COPY requirements.txt requirements.txt 6 | 7 | RUN pip3 install --upgrade pip setuptools wheel 8 | RUN pip3 install --no-warn-script-location --no-cache-dir -r requirements.txt 9 | 10 | COPY . . 11 | 12 | CMD ["python3", "main.py", "-a", "2"] -------------------------------------------------------------------------------- /INSTALL.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Creating virtual environment... 3 | python -m venv venv 4 | echo Activating virtual environment... 5 | call venv\Scripts\activate 6 | echo Installing dependencies... 7 | pip install -r requirements.txt 8 | echo Copying .env-example to .env... 9 | copy .env-example .env 10 | echo Please edit the .env file to add your API_ID and API_HASH. 11 | pause 12 | -------------------------------------------------------------------------------- /bot/utils/logger.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from loguru import logger 3 | 4 | 5 | logger.remove() 6 | logger.add(sink=sys.stdout, format="{time:YYYY-MM-DD HH:mm:ss}" 7 | " | {level: <8}" 8 | " | {line}" 9 | " - {message}") 10 | logger = logger.opt(colors=True) 11 | -------------------------------------------------------------------------------- /bot/config/config.py: -------------------------------------------------------------------------------- 1 | from pydantic_settings import BaseSettings, SettingsConfigDict 2 | 3 | 4 | class Settings(BaseSettings): 5 | model_config = SettingsConfigDict(env_file=".env", env_ignore_empty=True) 6 | 7 | API_ID: int 8 | API_HASH: str 9 | 10 | SLEEP_BETWEEN_TAP: list[int] = [10, 25] 11 | CLICKS_FOR_SLEEP: list[int] = [100, 150] 12 | LONG_SLEEP_BETWEEN_TAP: list[int] = [6000, 7000] 13 | SLEEP_BY_MIN_ENERGY_IN_RANGE: list[int] = [300, 350] 14 | SHOW_BALANCE_EVERY_TAPS: int = 20 15 | 16 | USE_PROXY_FROM_FILE: bool = False 17 | 18 | 19 | settings = Settings() 20 | -------------------------------------------------------------------------------- /bot/core/headers.py: -------------------------------------------------------------------------------- 1 | headers = { 2 | 'accept': 'application/json, text/plain, */*', 3 | 'accept-language': 'ru,ru-RU;q=0.9,en-US;q=0.8,en;q=0.7', 4 | 'origin': 'https://www.yescoin.gold', 5 | 'referer': 'https://www.yescoin.gold/', 6 | 'sec-ch-ua': '"Android WebView";v="123", "Not:A-Brand";v="8", "Chromium";v="123"', 7 | 'sec-ch-ua-mobile': '?1', 8 | 'sec-ch-ua-platform': '"Android"', 9 | 'sec-fetch-dest': 'empty', 10 | 'sec-fetch-mode': 'cors', 11 | 'sec-fetch-site': 'same-site', 12 | 'user-agent': 'Mozilla/5.0 (Linux; Android 13; RMX3630 Build/TP1A.220905.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/123.0.6312.118 Mobile Safari/537.36', 13 | 'x-requested-with': 'org.telegram.messenger', 14 | } -------------------------------------------------------------------------------- /bot/core/registrator.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client 2 | 3 | from bot.config import settings 4 | from bot.utils import logger 5 | 6 | 7 | async def register_sessions() -> None: 8 | API_ID = settings.API_ID 9 | API_HASH = settings.API_HASH 10 | 11 | if not API_ID or not API_HASH: 12 | raise ValueError("API_ID and API_HASH not found in the .env file.") 13 | 14 | session_name = input('\nEnter the session name (press Enter to exit): ') 15 | 16 | if not session_name: 17 | return None 18 | 19 | session = Client( 20 | name=session_name, 21 | api_id=API_ID, 22 | api_hash=API_HASH, 23 | workdir="sessions/" 24 | ) 25 | 26 | async with session: 27 | user_data = await session.get_me() 28 | 29 | logger.success(f'Session added successfully @{user_data.username} | {user_data.first_name} {user_data.last_name}') 30 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # thx @AlexKrutoy 3 | #Проверка обновления репозитория 4 | echo "Check update...." 5 | git pull 6 | 7 | # Проверка на наличие папки venv 8 | if [ ! -d "venv" ]; then 9 | echo "Creating virtual environment..." 10 | python3 -m venv venv 11 | fi 12 | 13 | echo "Activating virtual environment..." 14 | source venv/bin/activate 15 | 16 | # Проверка на наличие установленного флага в виртуальном окружении 17 | if [ ! -f "venv/installed" ]; then 18 | if [ -f "requirements.txt" ]; then 19 | echo "Installing wheel for faster installing" 20 | pip3 install wheel 21 | echo "Installing dependencies..." 22 | pip3 install -r requirements.txt 23 | touch venv/installed 24 | else 25 | echo "requirements.txt not found, skipping dependency installation." 26 | fi 27 | else 28 | echo "Dependencies already installed, skipping installation." 29 | fi 30 | 31 | if [ ! -f ".env" ]; then 32 | echo "Copying configuration file" 33 | cp .env-example .env 34 | else 35 | echo "Skipping .env copying" 36 | fi 37 | 38 | echo "Starting the bot..." 39 | python3 main.py 40 | 41 | echo "done" 42 | echo "PLEASE EDIT .ENV FILE" 43 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | install_python() { 4 | echo "Select the Python version to install:" 5 | echo "1) Python 3.9" 6 | echo "2) Python 3.10" 7 | echo "3) Python 3.11" 8 | echo "4) Python 3.12" 9 | read -p "Enter the number of your choice: " choice 10 | 11 | case $choice in 12 | 1) version="3.9" ;; 13 | 2) version="3.10" ;; 14 | 3) version="3.11" ;; 15 | 4) version="3.12" ;; 16 | *) echo "Invalid choice"; exit 1 ;; 17 | esac 18 | 19 | if command -v apt-get &> /dev/null; then 20 | sudo apt-get update 21 | sudo apt-get install -y python$version python$version-venv python$version-pip 22 | elif command -v yum &> /dev/null; then 23 | sudo yum install -y https://repo.ius.io/ius-release-el$(rpm -E %{rhel}).rpm 24 | sudo yum install -y python$version python$version-venv python$version-pip 25 | elif command -v dnf &> /dev/null; then 26 | sudo dnf install -y python$version python$version-venv python$version-pip 27 | else 28 | echo "Package manager not supported. Please install Python manually." 29 | exit 1 30 | fi 31 | } 32 | 33 | if ! command -v python3 &> /dev/null; then 34 | install_python 35 | fi 36 | 37 | echo "Creating virtual environment..." 38 | python3 -m venv venv 39 | 40 | echo "Activating virtual environment..." 41 | source venv/bin/activate 42 | 43 | echo "Installing dependencies..." 44 | pip install -r requirements.txt 45 | 46 | echo "Copying .env-example to .env..." 47 | cp .env-example .env 48 | 49 | echo "Please edit the .env file to add your API_ID and API_HASH." 50 | read -p "Press any key to continue..." -------------------------------------------------------------------------------- /bot/plugins/manager.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | from pyrogram.types import Message 3 | 4 | from bot.utils import scripts 5 | from bot.utils.logger import logger 6 | from bot.utils.emojis import StaticEmoji 7 | from bot.utils.launcher import tg_clients, run_tasks 8 | 9 | 10 | @Client.on_message(filters.me & filters.chat("me") & filters.command("help", prefixes="/")) 11 | async def send_help(_: Client, message: Message): 12 | help_text = scripts.get_help_text() 13 | 14 | await message.edit(text=help_text) 15 | 16 | 17 | @Client.on_message(filters.me & filters.chat("me") & filters.command("tap", prefixes="/")) 18 | @scripts.with_args("This command does not work without arguments\n" 19 | "Type /tap on to start or /tap off to stop") 20 | async def launch_tapper(client: Client, message: Message): 21 | flag = scripts.get_command_args(message, "tap") 22 | 23 | flags_to_start = ["on", "start"] 24 | flags_to_stop = ["off", "stop"] 25 | 26 | if flag in flags_to_start: 27 | logger.info(f"The tapper is launched with the command /tap {flag}\n") 28 | 29 | await message.edit( 30 | text=f"{StaticEmoji.ACCEPT} Tapper launched! {StaticEmoji.START}") 31 | await run_tasks(tg_clients=tg_clients) 32 | elif flag in flags_to_stop: 33 | logger.info(f"Tapper stopped with /tap command {flag}\n") 34 | 35 | await scripts.stop_tasks(client=client) 36 | await message.edit( 37 | text=f"{StaticEmoji.ACCEPT} Tapper stopped! {StaticEmoji.STOP}") 38 | else: 39 | await message.edit( 40 | text=f"{StaticEmoji.DENY} This command only accepts the following arguments: on/off | start/stop") 41 | -------------------------------------------------------------------------------- /bot/utils/scripts.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from typing import Union 3 | 4 | from pyrogram import Client 5 | from pyrogram.types import Message 6 | 7 | from bot.utils.emojis import num, StaticEmoji 8 | 9 | 10 | def get_command_args( 11 | message: Union[Message, str], 12 | command: Union[str, list[str]] = None, 13 | prefixes: str = "/", 14 | ) -> str: 15 | if isinstance(message, str): 16 | return message.split(f"{prefixes}{command}", maxsplit=1)[-1].strip() 17 | 18 | if isinstance(command, str): 19 | args = message.text.split(f"{prefixes}{command}", maxsplit=1)[-1].strip() 20 | return args 21 | 22 | elif isinstance(command, list): 23 | for cmd in command: 24 | args = message.text.split(f"{prefixes}{cmd}", maxsplit=1)[-1] 25 | 26 | if args != message.text: 27 | return args.strip() 28 | 29 | return "" 30 | 31 | 32 | def with_args(text: str): 33 | def decorator(func): 34 | async def wrapped(client: Client, message: Message): 35 | if message.text and len(message.text.split()) == 1: 36 | await message.edit(f"{text}") 37 | else: 38 | return await func(client, message) 39 | 40 | return wrapped 41 | 42 | return decorator 43 | 44 | 45 | def get_help_text(): 46 | return f""" 47 | {StaticEmoji.FLAG} [Demo version] 48 | 49 | {num(1)} /help - Displays all available commands 50 | {num(2)} /tap [on|start, off|stop] - Starts or stops the tapper 51 | 52 | """ 53 | 54 | 55 | 56 | async def stop_tasks(client: Client = None) -> None: 57 | if client: 58 | all_tasks = asyncio.all_tasks(loop=client.loop) 59 | else: 60 | loop = asyncio.get_event_loop() 61 | all_tasks = asyncio.all_tasks(loop=loop) 62 | 63 | clicker_tasks = [task for task in all_tasks 64 | if isinstance(task, asyncio.Task) and task._coro.__name__ == 'run_tapper'] 65 | 66 | for task in clicker_tasks: 67 | try: 68 | task.cancel() 69 | except: 70 | ... 71 | -------------------------------------------------------------------------------- /README-EN.md: -------------------------------------------------------------------------------- 1 | [](https://t.me/gh0st1337) 2 | 3 | ![img1](.github/images/demo.png) 4 | 5 | > 🇷🇺 README на русском доступен [здесь](README.md) 6 | 7 | ## Features 8 | | Feature | Supported | 9 | |------------------------------------------------------------------|:--------------:| 10 | | Multithreading | ✅ | 11 | | Proxy binding to session | ✅ | 12 | | Random sleep time between clicks | ✅ | 13 | | Random number of clicks per request | ✅ | 14 | | Support for tdata / pyrogram .session | ✅ | 15 | 16 | 17 | ## [Settings](https://github.com/DARKM00N1337/ShitCoinTapBot/blob/main/.env-example) 18 | | Setting | Description | 19 | |---------------------------------|---------------------------------------------------------------------------| 20 | | **API_ID / API_HASH** | Data of the platform to launch the Telegram session (default - Android) | 21 | | **SLEEP_BETWEEN_TAP** | Sleep time between a series of clicks (e.g., 10, 25) | 22 | | **CLICKS_FOR_SLEEP** | Number of clicks before sleep (e.g., 100, 150) | 23 | | **LONG_SLEEP_BETWEEN_TAP** | Sleep time for energy accumulation (e.g., 6000, 7000) | 24 | | **SLEEP_BY_MIN_ENERGY_IN_RANGE**| Amount of energy at which the bot will go for a long sleep (e.g., 300, 350)| 25 | | **SHOW_BALANCE_EVERY_TAPS** | How often to show balance and energy (e.g., 20) | 26 | | **USE_PROXY_FROM_FILE** | Whether to use proxies from `bot/config/proxies.txt` file (True / False) | 27 | 28 | 29 | ## Installation 30 | You can download the [**Repository**](https://github.com/DARKM00N1337/ShitCoinTapBot) by cloning it to your system and installing the necessary dependencies: 31 | ```shell 32 | ~ >>> git clone https://github.com/DARKM00N1337/ShitCoinTapBot.git 33 | ~ >>> cd ShitCoinTapBot 34 | 35 | # Linux 36 | ~/ShitCoinTapBot >>> python3 -m venv venv 37 | ~/ShitCoinTapBot >>> source venv/bin/activate 38 | ~/ShitCoinTapBot >>> pip3 install -r requirements.txt 39 | ~/ShitCoinTapBot >>> cp .env-example .env 40 | ~/ShitCoinTapBot >>> nano .env # You must specify your API_ID and API_HASH here, the rest is taken by default 41 | ~/ShitCoinTapBot >>> python3 main.py 42 | 43 | # Windows 44 | ~/ShitCoinTapBot >>> python -m venv venv 45 | ~/ShitCoinTapBot >>> venv\Scripts\activate 46 | ~/ShitCoinTapBot >>> pip install -r requirements.txt 47 | ~/ShitCoinTapBot >>> copy .env-example .env 48 | ~/ShitCoinTapBot >>> # Specify your API_ID and API_HASH, the rest is taken by default 49 | ~/ShitCoinTapBot >>> python main.py 50 | ``` 51 | 52 | You can also use arguments for quick start, for example: 53 | ```shell 54 | ~/ShitCoinTapBot >>> python3 main.py --action (1/2) 55 | # Or 56 | ~/ShitCoinTapBot >>> python3 main.py -a (1/2) 57 | 58 | # 1 - Creates a session 59 | # 2 - Starts the clicker 60 | 61 | ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [](https://t.me/gh0st1337) 2 | 3 | 4 | ![img1](.github/images/demo.png) 5 | 6 | > 🇪🇳 README in english available [here](README-EN.md) 7 | 8 | ## Функционал 9 | | Функционал | Поддерживается | 10 | |----------------------------------------------------------------|:---------------:| 11 | | Многопоточность | ✅ | 12 | | Привязка прокси к сессии | ✅ | 13 | | Рандомное время сна между кликами | ✅ | 14 | | Рандомное количество кликов за запрос | ✅ | 15 | | Поддержка tdata / pyrogram .session | ✅ | 16 | 17 | 18 | ## [Настройки](https://github.com/DARKM00N1337/ShitCoinTapBot/blob/main/.env-example) 19 | | Настройка | Описание | 20 | |----------------------------------|-------------------------------------------------------------------------| 21 | | **API_ID / API_HASH** | Данные платформы, с которой запускать сессию Telegram (сток - Android) | 22 | | **SLEEP_BETWEEN_TAP** | Время сна между чередой кликов (напр. 10, 25) | 23 | | **CLICKS_FOR_SLEEP** | Количество кликов до сна (напр. 100, 150) | 24 | | **LONG_SLEEP_BETWEEN_TAP** | Время сна для ожидания накопления энергии (напр. 6000, 7000) | 25 | | **SLEEP_BY_MIN_ENERGY_IN_RANGE** | Количество энергии при котором бот уйдет в долгий сон (напр. 300, 350) | 26 | | **SHOW_BALANCE_EVERY_TAPS** | Каждые сколько тапов показывать баланс и энергию (напр. 20) | 27 | | **USE_PROXY_FROM_FILE** | Использовать-ли прокси из файла `bot/config/proxies.txt` (True / False) | 28 | 29 | 30 | ## Установка 31 | Вы можете скачать [**Репозиторий**](https://github.com/DARKM00N1337/ShitCoinTapBot) клонированием на вашу систему и установкой необходимых зависимостей: 32 | ```shell 33 | ~ >>> git clone https://github.com/DARKM00N1337/ShitCoinTapBot.git 34 | ~ >>> cd ShitCoinTapBot 35 | 36 | 37 | # Linux 38 | ~/ShitCoinTapBot >>> python3 -m venv venv 39 | ~/ShitCoinTapBot >>> source venv/bin/activate 40 | ~/ShitCoinTapBot >>> pip3 install -r requirements.txt 41 | ~/ShitCoinTapBot >>> cp .env-example .env 42 | ~/ShitCoinTapBot >>> nano .env # Здесь вы обязательно должны указать ваши API_ID и API_HASH , остальное берется по умолчанию 43 | ~/ShitCoinTapBot >>> python3 main.py 44 | 45 | # Windows 46 | ~/ShitCoinTapBot >>> python -m venv venv 47 | ~/ShitCoinTapBot >>> venv\Scripts\activate 48 | ~/ShitCoinTapBot >>> pip install -r requirements.txt 49 | ~/ShitCoinTapBot >>> copy .env-example .env 50 | ~/ShitCoinTapBot >>> # Указываете ваши API_ID и API_HASH, остальное берется по умолчанию 51 | ~/ShitCoinTapBot >>> python main.py 52 | ``` 53 | 54 | Также для быстрого запуска вы можете использовать аргументы, например: 55 | ```shell 56 | ~/ShitCoinTapBot >>> python3 main.py --action (1/2) 57 | # Или 58 | ~/ShitCoinTapBot >>> python3 main.py -a (1/2) 59 | 60 | # 1 - Создает сессию 61 | # 2 - Запускает кликер 62 | ``` 63 | 64 | 65 | -------------------------------------------------------------------------------- /bot/core/agents.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | 4 | def generate_random_user_agent(device_type='android', browser_type='chrome'): 5 | chrome_versions = list(range(110, 127)) 6 | firefox_versions = list(range(90, 100)) # Last 10 versions of Firefox 7 | 8 | if browser_type == 'chrome': 9 | major_version = random.choice(chrome_versions) 10 | minor_version = random.randint(0, 9) 11 | build_version = random.randint(1000, 9999) 12 | patch_version = random.randint(0, 99) 13 | browser_version = f"{major_version}.{minor_version}.{build_version}.{patch_version}" 14 | elif browser_type == 'firefox': 15 | browser_version = random.choice(firefox_versions) 16 | 17 | if device_type == 'android': 18 | android_versions = ['10.0', '11.0', '12.0', '13.0'] 19 | android_device = random.choice([ 20 | 'SM-G960F', 'Pixel 5', 'SM-A505F', 'Pixel 4a', 'Pixel 6 Pro', 'SM-N975F', 21 | 'SM-G973F', 'Pixel 3', 'SM-G980F', 'Pixel 5a', 'SM-G998B', 'Pixel 4', 22 | 'SM-G991B', 'SM-G996B', 'SM-F711B', 'SM-F916B', 'SM-G781B', 'SM-N986B', 23 | 'SM-N981B', 'Pixel 2', 'Pixel 2 XL', 'Pixel 3 XL', 'Pixel 4 XL', 24 | 'Pixel 5 XL', 'Pixel 6', 'Pixel 6 XL', 'Pixel 6a', 'Pixel 7', 'Pixel 7 Pro', 25 | 'OnePlus 8', 'OnePlus 8 Pro', 'OnePlus 9', 'OnePlus 9 Pro', 'OnePlus Nord', 'OnePlus Nord 2', 26 | 'OnePlus Nord CE', 'OnePlus 10', 'OnePlus 10 Pro', 'OnePlus 10T', 'OnePlus 10T Pro', 27 | 'Xiaomi Mi 9', 'Xiaomi Mi 10', 'Xiaomi Mi 11', 'Xiaomi Redmi Note 8', 'Xiaomi Redmi Note 9', 28 | 'Huawei P30', 'Huawei P40', 'Huawei Mate 30', 'Huawei Mate 40', 'Sony Xperia 1', 29 | 'Sony Xperia 5', 'LG G8', 'LG V50', 'LG V60', 'Nokia 8.3', 'Nokia 9 PureView' 30 | ]) 31 | android_version = random.choice(android_versions) 32 | if browser_type == 'chrome': 33 | return (f"Mozilla/5.0 (Linux; Android {android_version}; {android_device}) AppleWebKit/537.36 " 34 | f"(KHTML, like Gecko) Chrome/{browser_version} Mobile Safari/537.36") 35 | elif browser_type == 'firefox': 36 | return (f"Mozilla/5.0 (Android {android_version}; Mobile; rv:{browser_version}.0) " 37 | f"Gecko/{browser_version}.0 Firefox/{browser_version}.0") 38 | 39 | elif device_type == 'ios': 40 | ios_versions = ['13.0', '14.0', '15.0', '16.0'] 41 | ios_version = random.choice(ios_versions) 42 | if browser_type == 'chrome': 43 | return (f"Mozilla/5.0 (iPhone; CPU iPhone OS {ios_version.replace('.', '_')} like Mac OS X) " 44 | f"AppleWebKit/537.36 (KHTML, like Gecko) CriOS/{browser_version} Mobile/15E148 Safari/604.1") 45 | elif browser_type == 'firefox': 46 | return (f"Mozilla/5.0 (iPhone; CPU iPhone OS {ios_version.replace('.', '_')} like Mac OS X) " 47 | f"AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/{browser_version}.0 Mobile/15E148 Safari/605.1.15") 48 | 49 | elif device_type == 'windows': 50 | windows_versions = ['10.0', '11.0'] 51 | windows_version = random.choice(windows_versions) 52 | if browser_type == 'chrome': 53 | return (f"Mozilla/5.0 (Windows NT {windows_version}; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " 54 | f"Chrome/{browser_version} Safari/537.36") 55 | elif browser_type == 'firefox': 56 | return (f"Mozilla/5.0 (Windows NT {windows_version}; Win64; x64; rv:{browser_version}.0) " 57 | f"Gecko/{browser_version}.0 Firefox/{browser_version}.0") 58 | 59 | elif device_type == 'ubuntu': 60 | if browser_type == 'chrome': 61 | return (f"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:94.0) AppleWebKit/537.36 (KHTML, like Gecko) " 62 | f"Chrome/{browser_version} Safari/537.36") 63 | elif browser_type == 'firefox': 64 | return (f"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:{browser_version}.0) Gecko/{browser_version}.0 " 65 | f"Firefox/{browser_version}.0") 66 | 67 | return None -------------------------------------------------------------------------------- /bot/utils/launcher.py: -------------------------------------------------------------------------------- 1 | import os 2 | import glob 3 | import asyncio 4 | import argparse 5 | from itertools import cycle 6 | 7 | from pyrogram import Client, compose 8 | from better_proxy import Proxy 9 | 10 | from bot.config import settings 11 | from bot.utils import logger 12 | from bot.core.tapper import run_tapper 13 | from bot.core.registrator import register_sessions 14 | 15 | 16 | start_text = """ 17 | 18 | ████████ ██ ██ ██ ██████████ ██████ ███████ ██ ████ ██ ██████ ███████ ██████████ 19 | ██░░░░░░ ░██ ░██░██░░░░░██░░░ ██░░░░██ ██░░░░░██ ░██░██░██ ░██ ░█░░░░██ ██░░░░░██ ░░░░░██░░░ 20 | ░██ ░██ ░██░██ ░██ ██ ░░ ██ ░░██░██░██░░██ ░██ ░█ ░██ ██ ░░██ ░██ 21 | ░█████████░██████████░██ ░██ ░██ ░██ ░██░██░██ ░░██ ░██ ░██████ ░██ ░██ ░██ 22 | ░░░░░░░░██░██░░░░░░██░██ ░██ ░██ ░██ ░██░██░██ ░░██░██ ░█░░░░ ██░██ ░██ ░██ 23 | ░██░██ ░██░██ ░██ ░░██ ██░░██ ██ ░██░██ ░░████ ░█ ░██░░██ ██ ░██ 24 | ████████ ░██ ░██░██ ░██ ░░██████ ░░███████ ░██░██ ░░███ ░███████ ░░███████ ░██ 25 | ░░░░░░░░ ░░ ░░ ░░ ░░ ░░░░░░ ░░░░░░░ ░░ ░░ ░░░ ░░░░░░░ ░░░░░░░ ░░ 26 | 27 | 28 | Made by @gh0st1337 and @x1darkm00n1x 29 | 30 | Our channel: @darkm00n_fuck 31 | 32 | Select an action: 33 | 34 | 1. Create session 35 | 2. Run clicker 36 | """ 37 | 38 | global tg_clients 39 | 40 | def get_session_names() -> list[str]: 41 | session_names = glob.glob("sessions/*.session") 42 | session_names = [ 43 | os.path.splitext(os.path.basename(file))[0] for file in session_names 44 | ] 45 | 46 | return session_names 47 | 48 | 49 | def get_proxies() -> list[Proxy]: 50 | if settings.USE_PROXY_FROM_FILE: 51 | with open(file="bot/config/proxies.txt", encoding="utf-8-sig") as file: 52 | proxies = [Proxy.from_str(proxy=row.strip()).as_url for row in file] 53 | else: 54 | proxies = [] 55 | 56 | return proxies 57 | 58 | 59 | async def get_tg_clients() -> list[Client]: 60 | global tg_clients 61 | 62 | session_names = get_session_names() 63 | 64 | if not session_names: 65 | raise FileNotFoundError("Not found session files") 66 | 67 | if not settings.API_ID or not settings.API_HASH: 68 | raise ValueError("API_ID and API_HASH not found in the .env file.") 69 | 70 | tg_clients = [ 71 | Client( 72 | name=session_name, 73 | api_id=settings.API_ID, 74 | api_hash=settings.API_HASH, 75 | workdir="sessions/", 76 | plugins=dict(root="bot/plugins"), 77 | ) 78 | for session_name in session_names 79 | ] 80 | 81 | return tg_clients 82 | 83 | 84 | async def process() -> None: 85 | parser = argparse.ArgumentParser() 86 | parser.add_argument("-a", "--action", type=int, help="Action to perform") 87 | 88 | logger.info(f"Detected {len(get_session_names())} sessions | {len(get_proxies())} proxies") 89 | 90 | action = parser.parse_args().action 91 | 92 | if not action: 93 | print(start_text) 94 | 95 | while True: 96 | action = input("> ") 97 | 98 | if not action.isdigit(): 99 | logger.warning("Action must be number") 100 | elif action not in ["1", "2"]: 101 | logger.warning("Action must be 1 or 2") 102 | else: 103 | action = int(action) 104 | break 105 | 106 | if action == 1: 107 | await register_sessions() 108 | elif action == 2: 109 | tg_clients = await get_tg_clients() 110 | 111 | await run_tasks(tg_clients=tg_clients) 112 | 113 | 114 | 115 | async def run_tasks(tg_clients: list[Client]): 116 | proxies = get_proxies() 117 | proxies_cycle = cycle(proxies) if proxies else None 118 | tasks = [ 119 | asyncio.create_task( 120 | run_tapper( 121 | tg_client=tg_client, 122 | proxy=next(proxies_cycle) if proxies_cycle else None, 123 | ) 124 | ) 125 | for tg_client in tg_clients 126 | ] 127 | 128 | await asyncio.gather(*tasks) 129 | -------------------------------------------------------------------------------- /bot/utils/emojis.py: -------------------------------------------------------------------------------- 1 | import random 2 | from enum import Enum 3 | 4 | 5 | class StaticEmoji(str, Enum): 6 | ACCEPT = '✔️' 7 | DENY = '' 8 | WARNING = '⚠️' 9 | LOUDSPEAKER = '📣' 10 | FLAG = '🔖' 11 | SCRAP = '📌' 12 | ARROW = '➡️' 13 | PLUS = '' 14 | DOLLAR = '💵' 15 | START = '🟢' 16 | STOP = '🔴' 17 | 18 | 19 | def get_random_reaction(): 20 | reactions = [ 21 | "👍", "👎", "❤️", "🔥", "🥰", "👏", "😁", "🤔", "🤯", "😱", "🤬", "😢", "🎉", "🤩", "🤮", "💩", "🙏", "👌", "🕊", "🤡", "🥱", "🥴", 22 | "😍", "🐳", "❤️‍🔥", "🌚", "🌭", "💯", "🤣", "⚡️", "🍌", "🏆", "💔", "🤨", "😐", "🍓", "🍾", "💋", "🖕", "😈", "😴", "😭", "🤓", 23 | "👻", "👨‍💻", "👀", "🎃", "🙈", "😇", "😨", "🤝", "✍️", "🤗", "🫡", "🎅", "🎄", "☃️", "💅", "🤪", "🗿", "🆒", "💘", "🙉", "🦄", 24 | "😘", "💊", "🙊", "😎", "👾", "🤷‍♂️", "🤷", "🤷‍♀️", "😡" 25 | ] 26 | 27 | return random.choice(reactions) 28 | 29 | 30 | accept = [ 31 | '🌟', 32 | '🌟', 33 | '🌟', 34 | '🌟', 35 | '🌟', 36 | '🌟', 37 | '🌟', 38 | '🌟', 39 | '🌟', 40 | '🌟', 41 | '🌟', 42 | '🌟', 43 | '🌟', 44 | '🌟', 45 | '🌟', 46 | '🌟', 47 | '', 48 | '', 49 | '', 50 | '', 51 | '', 52 | '', 53 | '', 54 | '', 55 | '', 56 | '', 57 | '', 58 | '', 59 | '', 60 | '', 61 | '', 62 | '', 63 | '', 64 | '', 65 | '', 66 | '', 67 | '', 68 | '', 69 | ] 70 | 71 | deny = [ 72 | "", 73 | "", 74 | "", 75 | "", 76 | "", 77 | "", 78 | ] 79 | 80 | warnings = [ 81 | "⚠️", 82 | "⚠️", 83 | "⚠️", 84 | "⚠️", 85 | "⚠️", 86 | "⚠️", 87 | ] 88 | 89 | nums = { 90 | 0: '🔠', 91 | 1: '🔠', 92 | 2: '🔠', 93 | 3: '🔠', 94 | 4: '🔠', 95 | 5: '🔠', 96 | 6: '🔠', 97 | 7: '🔠', 98 | 8: '🔠', 99 | 9: '🔠', 100 | } 101 | 102 | loads = [ 103 | "🫥", 104 | "🫥", 105 | "🫥", 106 | "🫥", 107 | "🫥", 108 | "🫥", 109 | "🫥", 110 | "🫥", 111 | "🫥", 112 | "🫠", 113 | "🫥", 114 | "🫥", 115 | "🫥", 116 | "🫥", 117 | "🫥", 118 | "🫥", 119 | "🫥", 120 | "🫥", 121 | "🫥", 122 | "🫥", 123 | "😵", 124 | "", 125 | "💫", 126 | "🫥", 127 | ] 128 | 129 | 130 | def rload(): 131 | return random.choice(loads) 132 | 133 | 134 | def rcheck(): 135 | return random.choice(accept) 136 | 137 | 138 | def rdeny(): 139 | return random.choice(deny) 140 | 141 | 142 | def rwarning(): 143 | return random.choice(warnings) 144 | 145 | 146 | def num(n): 147 | return nums[int(n)] 148 | -------------------------------------------------------------------------------- /bot/core/tapper.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from random import randint 3 | from urllib.parse import unquote 4 | import json 5 | import os 6 | import sys 7 | import psutil 8 | from pyrogram import Client 9 | from pyrogram.errors import Unauthorized, UserDeactivated, AuthKeyUnregistered 10 | from pyrogram.raw.functions.messages import RequestAppWebView 11 | from pyrogram.raw.types import InputBotAppShortName 12 | import base64 13 | import aiohttp 14 | from aiohttp_proxy import ProxyConnector, ProxyType 15 | from better_proxy import Proxy 16 | from bot.config import settings 17 | from bot.utils import logger 18 | from bot.exceptions import InvalidSession 19 | from .headers import headers 20 | from .agents import generate_random_user_agent 21 | 22 | class Tapper: 23 | def __init__(self, tg_client: Client): 24 | self.session_name = tg_client.name 25 | self.tg_client = tg_client 26 | self.is_tapping = False 27 | self.click_counter = 0 28 | self.random_clicks_threshold = randint(a=settings.CLICKS_FOR_SLEEP[0], b=settings.CLICKS_FOR_SLEEP[1]) 29 | self.tasks_checked = False 30 | self.proxy = None 31 | 32 | async def get_tg_web_data(self, proxy: str | None) -> str: 33 | if proxy: 34 | self.proxy = Proxy.from_str(proxy) 35 | proxy_dict = dict( 36 | scheme=self.proxy.protocol, 37 | hostname=self.proxy.host, 38 | port=self.proxy.port, 39 | username=self.proxy.login, 40 | password=self.proxy.password 41 | ) 42 | else: 43 | proxy_dict = None 44 | 45 | self.tg_client.proxy = proxy_dict 46 | 47 | try: 48 | with_tg = True 49 | 50 | if not self.tg_client.is_connected: 51 | with_tg = False 52 | try: 53 | await self.tg_client.connect() 54 | except (Unauthorized, UserDeactivated, AuthKeyUnregistered): 55 | raise InvalidSession(self.session_name) 56 | 57 | bot = await self.tg_client.resolve_peer('ShitCoinTap_Bot') 58 | app = InputBotAppShortName(bot_id=bot, short_name="Game") 59 | web_view = await self.tg_client.invoke(RequestAppWebView( 60 | peer=bot, 61 | app=app, 62 | platform='android', 63 | write_allowed=True 64 | )) 65 | 66 | auth_url = web_view.url 67 | tg_web_data = unquote( 68 | string=unquote( 69 | string=auth_url.split('tgWebAppData=', maxsplit=1)[1].split('&tgWebAppVersion', maxsplit=1)[0])) 70 | 71 | if with_tg is False: 72 | await self.tg_client.disconnect() 73 | 74 | return tg_web_data 75 | 76 | except InvalidSession as error: 77 | raise error 78 | 79 | except Exception as error: 80 | logger.error(f"{self.session_name} | Unknown error during Authorization: {error}") 81 | await asyncio.sleep(delay=3) 82 | 83 | async def connect(self, user_id: int, init_data: str): 84 | init_data_base64 = base64.b64encode(init_data.encode()).decode() 85 | url = f"wss://cmonkey.vip/api/users/{user_id}/actions?init-data={init_data_base64}" 86 | user_agent = generate_random_user_agent(device_type='android', browser_type='chrome') 87 | 88 | headers = { 89 | 'Accept': '*/*', 90 | 'Accept-Language': 'ru,en;q=0.9', 91 | 'Connection': 'keep-alive', 92 | 'Content-Type': 'application/json', 93 | 'Host': 'cmonkey.vip', 94 | 'Origin': 'https://sexyzbot.pxlvrs.io', 95 | 'Referer': 'https://cmonkey.vip/', 96 | 'Sec-Fetch-Dest': 'empty', 97 | 'Sec-Fetch-Mode': 'cors', 98 | 'Sec-Fetch-Site': 'same-origin', 99 | "User-Agent": user_agent 100 | } 101 | 102 | proxy = None 103 | if self.proxy: 104 | proxy = f"http://{self.proxy.host}:{self.proxy.port}" 105 | proxy_auth = aiohttp.BasicAuth(self.proxy.login, self.proxy.password) 106 | else: 107 | proxy_auth = None 108 | 109 | async with aiohttp.ClientSession() as session: 110 | async with session.ws_connect( 111 | url, 112 | headers=headers, 113 | proxy=proxy, 114 | proxy_auth=proxy_auth 115 | ) as websocket: 116 | await self.send_message(websocket) 117 | await self.listen(websocket, init_data_base64) 118 | 119 | async def reconnect(self, user_id: int, init_data: str): 120 | await asyncio.sleep(90) 121 | await self.connect(user_id, init_data) 122 | 123 | async def listen(self, websocket, init_data_base64: str): 124 | try: 125 | async for message in websocket: 126 | await self.handle_message(message, websocket, init_data_base64) 127 | except aiohttp.WSServerHandshakeError as e: 128 | logger.error(f"{self.session_name} | Disconnected. ERROR: {e}") 129 | 130 | async def send_minigame(self, websocket): 131 | message = {"type": "minigame", "success": True, "result": 3500} 132 | await websocket.send_json(message) 133 | 134 | async def send_message(self, websocket): 135 | if not websocket.closed: 136 | message = {"type": "game", "click": 1} 137 | await websocket.send_json(message) 138 | self.click_counter += 1 139 | if self.click_counter >= self.random_clicks_threshold: 140 | await self.sleep_random_short() 141 | self.click_counter = 0 142 | self.random_clicks_threshold = randint(a=settings.CLICKS_FOR_SLEEP[0], b=settings.CLICKS_FOR_SLEEP[1]) 143 | else: 144 | logger.info(f"{self.session_name} | Nothing was sent to websocket") 145 | 146 | async def check_memory_usage(self): 147 | # !!!!!!Проверка использования памяти и перезапуск при превышении лимита!!!!!!!!!! 148 | process = psutil.Process(os.getpid()) 149 | while True: 150 | memory_info = process.memory_info() 151 | heap_total = psutil.virtual_memory().total 152 | if memory_info.rss > 0.8 * heap_total: 153 | logger.error(f"{self.session_name} | Restarting...") 154 | sys.exit(1) 155 | await asyncio.sleep(10) 156 | 157 | async def sleep_with_random_delay(self): 158 | delay = randint(a=settings.LONG_SLEEP_BETWEEN_TAP[0], b=settings.LONG_SLEEP_BETWEEN_TAP[1]) 159 | logger.info( 160 | f"{self.session_name} | Sleeping for {delay} seconds. ") 161 | await asyncio.sleep(delay) 162 | 163 | async def sleep_random_short(self): 164 | delay = randint(a=settings.SLEEP_BETWEEN_TAP[0], b=settings.SLEEP_BETWEEN_TAP[1]) 165 | logger.info(f"{self.session_name} | Sleeping for {delay} seconds.") 166 | await asyncio.sleep(delay) 167 | 168 | async def handle_message(self, message, websocket, init_data_base64: str): 169 | try: 170 | data = json.loads(message.data) 171 | 172 | if data["energy"] % settings.SHOW_BALANCE_EVERY_TAPS == 0: 173 | logger.info( 174 | f"{self.session_name} | Tapping | Energy: {data['energy']} | Balance: {data['coins']}") 175 | 176 | if data["energy"] < randint(a=settings.SLEEP_BY_MIN_ENERGY_IN_RANGE[0], b=settings.SLEEP_BY_MIN_ENERGY_IN_RANGE[1]): 177 | logger.info(f"{self.session_name} | Energy is low: {data['energy']}. Sleeping. | Balance: {data['coins']}") 178 | self.is_tapping = False 179 | await self.sleep_with_random_delay() 180 | await self.reconnect(await self.get_user_id(), await self.get_tg_web_data(self.tg_client.proxy)) 181 | elif data.get("minigame"): 182 | await self.send_minigame(websocket) 183 | logger.success(f"{self.session_name} | Minigame! ") 184 | else: 185 | if not self.is_tapping: 186 | logger.success(f"{self.session_name} | Start tapping! | ") 187 | self.is_tapping = True 188 | await self.send_message(websocket) 189 | 190 | if not self.tasks_checked: 191 | await self.check_and_complete_tasks(init_data_base64) 192 | self.tasks_checked = True 193 | 194 | except json.JSONDecodeError as e: 195 | logger.error(f"{self.session_name} | Error: {e}") 196 | await self.reconnect(await self.get_user_id(), await self.get_tg_web_data(self.tg_client.proxy)) 197 | 198 | async def check_proxy(self, http_client: aiohttp.ClientSession, proxy: Proxy) -> None: 199 | try: 200 | response = await http_client.get(url='https://httpbin.org/ip', timeout=aiohttp.ClientTimeout(5)) 201 | ip = (await response.json()).get('origin') 202 | logger.info(f"{self.session_name} | Proxy IP: {ip}") 203 | except Exception as error: 204 | logger.error(f"{self.session_name} | Proxy: {proxy} | Error: {error}") 205 | 206 | async def get_user_id(self) -> int: 207 | try: 208 | if not self.tg_client.is_connected: 209 | await self.tg_client.connect() 210 | 211 | me = await self.tg_client.get_me() 212 | user_id = me.id 213 | return user_id 214 | except Exception as error: 215 | logger.error(f"{self.session_name} | Error getting user ID: {error}") 216 | raise error 217 | 218 | async def get_tasks(self, init_data_base64: str) -> list: 219 | headers = { 220 | "accept": "*/*", 221 | "accept-language": "ru,en;q=0.9", 222 | "cache-control": "no-cache", 223 | "content-type": "application/json", 224 | "init-data": init_data_base64, 225 | "pragma": "no-cache", 226 | "sec-fetch-dest": "empty", 227 | "sec-fetch-mode": "cors", 228 | "sec-fetch-site": "same-origin", 229 | "User-Agent": generate_random_user_agent(device_type='android', browser_type='chrome') 230 | } 231 | 232 | if self.proxy: 233 | connector = ProxyConnector( 234 | proxy_type=ProxyType.HTTP, 235 | host=self.proxy.host, 236 | port=self.proxy.port, 237 | username=self.proxy.login, 238 | password=self.proxy.password 239 | ) 240 | else: 241 | connector = None 242 | 243 | async with aiohttp.ClientSession(connector=connector) as session: 244 | async with session.get( 245 | 'https://cmonkey.vip/api/users/tasks', 246 | headers=headers 247 | ) as response: 248 | if response.status == 200: 249 | data = await response.json() 250 | return data.get('tasks', []) 251 | else: 252 | logger.error(f"{self.session_name} | Failed to fetch tasks with status: {response.status}") 253 | return [] 254 | 255 | async def complete_task(self, task_id: int, init_data_base64: str): 256 | headers = { 257 | "accept": "*/*", 258 | "accept-language": "ru,en;q=0.9", 259 | "cache-control": "no-cache", 260 | "content-type": "application/json", 261 | "init-data": init_data_base64, 262 | "pragma": "no-cache", 263 | "sec-fetch-dest": "empty", 264 | "sec-fetch-mode": "cors", 265 | "sec-fetch-site": "same-origin", 266 | "User-Agent": generate_random_user_agent(device_type='android', browser_type='chrome') 267 | } 268 | 269 | payload = json.dumps({"task": task_id}) 270 | 271 | if self.proxy: 272 | connector = ProxyConnector( 273 | proxy_type=ProxyType.HTTP, 274 | host=self.proxy.host, 275 | port=self.proxy.port, 276 | username=self.proxy.login, 277 | password=self.proxy.password 278 | ) 279 | else: 280 | connector = None 281 | 282 | async with aiohttp.ClientSession(connector=connector) as session: 283 | async with session.put( 284 | 'https://cmonkey.vip/api/users/tasks', 285 | headers=headers, 286 | data=payload 287 | ) as response: 288 | if response.status == 200: 289 | data = await response.json() 290 | logger.info(f"{self.session_name} | Task {task_id} updated successfully: {data.get('message')}") 291 | else: 292 | logger.error(f"{self.session_name} | Failed to complete task {task_id} with status: {response.status} - {await response.text()}") 293 | 294 | async def check_and_complete_tasks(self, init_data_base64: str): 295 | tasks = await self.get_tasks(init_data_base64) 296 | for task in tasks: 297 | if task['id'] in [1, 2, 3] and not task['completed']: 298 | await self.complete_task(task['id'], init_data_base64) 299 | await asyncio.sleep(1) # Add a delay between tasks to avoid being rate-limited 300 | 301 | async def run(self, proxy: str | None) -> None: 302 | 303 | proxy_conn = ProxyConnector.from_url(proxy) if proxy else None 304 | 305 | async with aiohttp.ClientSession(headers=headers, connector=proxy_conn) as http_client: 306 | if proxy: 307 | await self.check_proxy(http_client=http_client, proxy=proxy) 308 | 309 | while True: 310 | try: 311 | tg_web_data = await self.get_tg_web_data(proxy=proxy) 312 | user_id = await self.get_user_id() 313 | await self.connect(user_id, tg_web_data) 314 | 315 | except InvalidSession as error: 316 | raise error 317 | 318 | except Exception as error: 319 | logger.error(f"{self.session_name} | Unknown error: {error}") 320 | await asyncio.sleep(delay=3) 321 | 322 | 323 | async def run_tapper(tg_client: Client, proxy: str | None): 324 | try: 325 | await Tapper(tg_client=tg_client).run(proxy=proxy) 326 | except InvalidSession: 327 | logger.error(f"{tg_client.name} | Invalid Session") 328 | --------------------------------------------------------------------------------