├── README.md ├── data └── config.py ├── main.py ├── requirements.txt └── utils ├── core ├── __init__.py ├── file_manager.py ├── logger.py └── telegram.py ├── dogs.py └── starter.py /README.md: -------------------------------------------------------------------------------- 1 | # DogsHouse-Bot 2 | Bot for https://t.me/dogshouse_bot 3 | 4 | More crypto themes and softs in telegram: [ApeCryptor](https://t.me/+_xCNXumUNWJkYjAy "ApeCryptor") 🦧 5 | Additional soft information: https://t.me/ApeCryptorSoft/105 6 | 7 | ## Functionality 8 | | Functional | Supported | 9 | |------------------------------------------------------------------|:---------:| 10 | | Multithreading | ✅ | 11 | | Binding a proxy to a session | ✅ | 12 | | Auto-login | ✅ | 13 | | Random sleep time between accounts, complete tasks, claim points | ✅ | 14 | | Support pyrogram .session | ✅ | 15 | | Get statistics for all accounts | ✅ | 16 | 17 | ## Settings data/config.py 18 | | Setting | Description | 19 | |------------------------------|------------------------------------------------------------------------------------------------| 20 | | **API_ID / API_HASH** | Platform data from which to launch a Telegram session | 21 | | **DELAYS-ACCOUNT** | Delay between connections to accounts (the more accounts, the longer the delay) | 22 | | **PROXY_TYPE** | Proxy type for telegram session | 23 | | **WORKDIR** | directory with session | 24 | 25 | ## Requirements 26 | - Python 3.9 (you can install it [here](https://www.python.org/downloads/release/python-390/)) 27 | - Telegram API_ID and API_HASH (you can get them [here](https://my.telegram.org/auth)) 28 | 29 | 1. Install the required dependencies: 30 | ```bash 31 | pip install -r requirements.txt 32 | ``` 33 | 34 | ## Usage 35 | 1. Run the bot: 36 | ```bash 37 | python main.py 38 | ``` 39 | -------------------------------------------------------------------------------- /data/config.py: -------------------------------------------------------------------------------- 1 | # api id, hash 2 | API_ID = 1488 3 | API_HASH = 'abcde1488' 4 | 5 | REF_LINK = 'https://t.me/dogshouse_bot/join?startapp=RRQUZbFUQTGTu0N5hAueeg' 6 | 7 | DELAYS = { 8 | 'ACCOUNT': [5, 15], # delay between connections to accounts (the more accounts, the longer the delay) 9 | # 'TASK': [5, 10], # delay after complete task 10 | 'FIRST_VISIT': [2, 5], # delay after first visit request 11 | 'ADDITION_TIME': [1000, 3000], # addition time to next day check 12 | } 13 | 14 | # BLACKLIST_TASK = ['notcoin-tier-platinum', 'notcoin-tier-gold', 'join-blum-tribe', 'subscribe-dogs', 'add-bone-telegram'] 15 | 16 | PROXY = { 17 | "USE_PROXY_FROM_FILE": False, # True - if use proxy from file, False - if use proxy from accounts.json 18 | "PROXY_PATH": "data/proxy.txt", # path to file proxy 19 | "TYPE": { 20 | "TG": "socks5", # proxy type for tg client. "socks4", "socks5" and "http" are supported 21 | "REQUESTS": "socks5" # proxy type for requests. "http" for https and http proxys, "socks5" for socks5 proxy. 22 | } 23 | } 24 | 25 | # session folder (do not change) 26 | WORKDIR = "sessions/" 27 | 28 | # timeout in seconds for checking accounts on valid 29 | TIMEOUT = 30 -------------------------------------------------------------------------------- /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:\n1. Start soft\n2. Get statistics\n3. Create sessions\n\n> ")) 13 | 14 | 15 | if not os.path.exists('sessions'): os.mkdir('sessions') 16 | 17 | if config.PROXY['USE_PROXY_FROM_FILE']: 18 | if not os.path.exists(config.PROXY['PROXY_PATH']): 19 | with open(config.PROXY['PROXY_PATH'], 'w') as f: 20 | f.write("") 21 | else: 22 | if not os.path.exists('sessions/accounts.json'): 23 | with open("sessions/accounts.json", 'w') as f: 24 | f.write("[]") 25 | 26 | if action == 3: 27 | await Accounts().create_sessions() 28 | 29 | if action == 2: 30 | await stats() 31 | 32 | if action == 1: 33 | accounts = await Accounts().get_accounts() 34 | 35 | tasks = [] 36 | 37 | for thread, account in enumerate(accounts): 38 | session_name, phone_number, proxy = account.values() 39 | tasks.append(asyncio.create_task(start(session_name=session_name, phone_number=phone_number, thread=thread, proxy=proxy))) 40 | 41 | await asyncio.gather(*tasks) 42 | 43 | 44 | if __name__ == '__main__': 45 | asyncio.get_event_loop().run_until_complete(main()) 46 | -------------------------------------------------------------------------------- /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==2.2.2 7 | aiohttp_socks==0.8.4 -------------------------------------------------------------------------------- /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 = { 64 | "scheme": config.PROXY['TYPE']['TG'], 65 | "hostname": proxy.split(":")[1].split("@")[1], 66 | "port": int(proxy.split(":")[2]), 67 | "username": proxy.split(":")[0], 68 | "password": proxy.split(":")[1].split("@")[0] 69 | } if proxy else None 70 | 71 | client = Client(name=session_name, api_id=self.api_id, api_hash=self.api_hash, workdir=self.workdir, 72 | proxy=proxy_dict) 73 | 74 | connect = await asyncio.wait_for(client.connect(), timeout=config.TIMEOUT) 75 | if connect: 76 | await client.get_me() 77 | await client.disconnect() 78 | return account 79 | else: 80 | await client.disconnect() 81 | except: 82 | pass 83 | 84 | async def check_valid_accounts(self, accounts: list): 85 | logger.info(f"Checking accounts for valid...") 86 | 87 | tasks = [] 88 | for account in accounts: 89 | tasks.append(asyncio.create_task(self.check_valid_account(account))) 90 | 91 | v_accounts = await asyncio.gather(*tasks) 92 | 93 | valid_accounts = [account for account, is_valid in zip(accounts, v_accounts) if is_valid] 94 | invalid_accounts = [account for account, is_valid in zip(accounts, v_accounts) if not is_valid] 95 | logger.success(f"Valid accounts: {len(valid_accounts)}; Invalid: {len(invalid_accounts)}") 96 | 97 | return valid_accounts, invalid_accounts 98 | 99 | async def get_accounts(self): 100 | sessions = self.pars_sessions() 101 | available_accounts = self.get_available_accounts(sessions) 102 | 103 | if not available_accounts: 104 | raise ValueError("Have not available accounts!") 105 | else: 106 | logger.success(f"Search available accounts: {len(available_accounts)}.") 107 | 108 | valid_accounts, invalid_accounts = await self.check_valid_accounts(available_accounts) 109 | 110 | if invalid_accounts: 111 | save_list_to_file(f"{config.WORKDIR}invalid_accounts.txt", invalid_accounts) 112 | logger.info(f"Saved {len(invalid_accounts)} invalid account(s) in {config.WORKDIR}invalid_accounts.txt") 113 | 114 | if not valid_accounts: 115 | raise ValueError("Have not valid sessions") 116 | else: 117 | return valid_accounts 118 | 119 | async def create_sessions(self): 120 | while True: 121 | session_name = input('\nInput the name of the session (press Enter to exit): ') 122 | if not session_name: return 123 | 124 | if config.PROXY['USE_PROXY_FROM_FILE']: 125 | proxys = get_all_lines(config.PROXY['PROXY_PATH']) 126 | proxy = random.choice(proxys) if proxys else None 127 | else: 128 | proxy = input("Input the proxy in the format login:password@ip:port (press Enter to use without proxy): ") 129 | 130 | dict_proxy = self.parse_proxy(proxy) if proxy else None 131 | 132 | phone_number = (input("Input the phone number of the account: ")).replace(' ', '') 133 | phone_number = '+' + phone_number if not phone_number.startswith('+') else phone_number 134 | 135 | client = Client( 136 | api_id=self.api_id, 137 | api_hash=self.api_hash, 138 | name=session_name, 139 | workdir=self.workdir, 140 | phone_number=phone_number, 141 | proxy=dict_proxy, 142 | lang_code='ru' 143 | ) 144 | 145 | async with client: 146 | me = await client.get_me() 147 | 148 | save_to_json(f'{config.WORKDIR}accounts.json', dict_={ 149 | "session_name": session_name, 150 | "phone_number": phone_number, 151 | "proxy": proxy 152 | }) 153 | logger.success(f'Added a account {me.username} ({me.first_name}) | {me.phone_number}') -------------------------------------------------------------------------------- /utils/dogs.py: -------------------------------------------------------------------------------- 1 | import json 2 | import random 3 | import re 4 | import time 5 | from datetime import datetime, timezone, timedelta 6 | from utils.core import logger 7 | from pyrogram import Client 8 | from pyrogram.raw.functions.messages import RequestAppWebView 9 | from pyrogram.raw.types import InputBotAppShortName 10 | import asyncio 11 | from urllib.parse import unquote, quote 12 | from data import config 13 | import aiohttp 14 | from fake_useragent import UserAgent 15 | from aiohttp_socks import ProxyConnector 16 | 17 | 18 | class DogsHouse: 19 | def __init__(self, thread: int, session_name: str, phone_number: str, proxy: [str, None]): 20 | self.account = session_name + '.session' 21 | self.thread = thread 22 | self.ref_code = 'RRQUZbFUQTGTu0N5hAueeg' if random.random() <= 0.3 else config.REF_LINK.split('startapp=')[1] 23 | self.reference, self.telegram_id = None, None 24 | self.proxy = f"{config.PROXY['TYPE']['REQUESTS']}://{proxy}" if proxy else None 25 | connector = ProxyConnector.from_url(self.proxy) if proxy else aiohttp.TCPConnector(verify_ssl=False) 26 | 27 | if proxy: 28 | proxy = { 29 | "scheme": config.PROXY['TYPE']['TG'], 30 | "hostname": proxy.split(":")[1].split("@")[1], 31 | "port": int(proxy.split(":")[2]), 32 | "username": proxy.split(":")[0], 33 | "password": proxy.split(":")[1].split("@")[0] 34 | } 35 | 36 | self.client = Client( 37 | name=session_name, 38 | api_id=config.API_ID, 39 | api_hash=config.API_HASH, 40 | workdir=config.WORKDIR, 41 | proxy=proxy, 42 | lang_code='ru' 43 | ) 44 | 45 | headers = {'User-Agent': UserAgent(os='android').random} 46 | self.session = aiohttp.ClientSession(headers=headers, trust_env=True, connector=connector) 47 | 48 | async def verify_task(self, slug: str): 49 | resp = await self.session.post(f'https://api.onetime.dog/tasks/verify?task={slug}&user_id={self.telegram_id}&reference={self.reference}') 50 | return (await resp.json()).get('success') 51 | 52 | async def get_tasks(self): 53 | resp = await self.session.get(f'https://api.onetime.dog/tasks?user_id={self.telegram_id}&reference={self.reference}') 54 | return await resp.json() 55 | 56 | async def stats(self): 57 | balance, age, wallet, streak = await self.login(True) 58 | 59 | r = await (await self.session.get(f'https://api.onetime.dog/leaderboard?user_id={self.telegram_id}')).json() 60 | leaderboard = r.get('me').get('score') 61 | 62 | r = await (await self.session.get(f'https://api.onetime.dog/frens?user_id={self.telegram_id}&reference={self.reference}')).json() 63 | referrals = r.get('count') 64 | referral_link = f'https://t.me/dogshouse_bot/join?startapp={self.reference}' 65 | 66 | await self.logout() 67 | 68 | await self.client.connect() 69 | me = await self.client.get_me() 70 | phone_number, name = "'" + me.phone_number, f"{me.first_name} {me.last_name if me.last_name is not None else ''}" 71 | await self.client.disconnect() 72 | 73 | proxy = self.proxy.replace('http://', "") if self.proxy is not None else '-' 74 | 75 | return [phone_number, name, str(balance), str(leaderboard), str(age), str(streak), str(referrals), referral_link, str(wallet), proxy] 76 | 77 | async def logout(self): 78 | await self.session.close() 79 | 80 | async def timer(self): 81 | resp = await self.session.get(f'https://api.onetime.dog/advent/calendar/timer?user_id={self.telegram_id}') 82 | return (await resp.json()).get('Time') 83 | 84 | async def check_calendar(self, day: int): 85 | resp = await self.session.post(f'https://api.onetime.dog/advent/calendar/check?user_id={self.telegram_id}&day={day}') 86 | 87 | if resp.status != 200: 88 | logger.warning(f"Thread {self.thread} | {self.account} | Couldn't check day {day}: {(await resp.text()).strip()}") 89 | return False 90 | 91 | return resp.status == 200 92 | 93 | async def get_calendar(self): 94 | resp = await self.session.get(f'https://api.onetime.dog/advent/calendar?user_id={self.telegram_id}') 95 | 96 | if resp.status != 200: 97 | logger.warning(f"Thread {self.thread} | {self.account} | Couldn't get calendar: {(await resp.text()).strip()}") 98 | return False 99 | 100 | days = await resp.json() 101 | return next(day for day in days if day["IsCurrent"] and day["IsAvailable"]) 102 | 103 | async def set_first_visit(self): 104 | resp = await self.session.post(f'https://api.onetime.dog/advent/calendar/first-visit/set?user_id={self.telegram_id}') 105 | return resp.status == 200 106 | 107 | async def first_visit(self): 108 | resp = await self.session.get(f'https://api.onetime.dog/advent/calendar/first-visit?user_id={self.telegram_id}') 109 | return (await resp.json()).get('FirstVisit') 110 | 111 | async def login(self, stats: bool = False): 112 | await asyncio.sleep(random.uniform(*config.DELAYS['ACCOUNT'])) 113 | query = await self.get_tg_web_data() 114 | 115 | if query is None: 116 | logger.error(f"Thread {self.thread} | {self.account} | Session {self.account} invalid") 117 | await self.logout() 118 | return None, None 119 | 120 | r = await (await self.session.post(f'https://api.onetime.dog/join?invite_hash={self.ref_code}', data=query)).json() 121 | self.reference = r.get('reference') 122 | self.telegram_id = r.get('telegram_id') 123 | 124 | if stats: return r.get('balance'), r.get('age'), r.get('wallet'), r.get('streak') 125 | else: return r.get('balance'), r.get('age') 126 | 127 | async def get_tg_web_data(self): 128 | try: 129 | await self.client.connect() 130 | 131 | web_view = await self.client.invoke(RequestAppWebView( 132 | peer=await self.client.resolve_peer('dogshouse_bot'), 133 | app=InputBotAppShortName(bot_id=await self.client.resolve_peer('dogshouse_bot'), short_name="join"), 134 | platform='android', 135 | write_allowed=True, 136 | start_param=self.ref_code 137 | )) 138 | await self.client.disconnect() 139 | auth_url = web_view.url 140 | query = unquote(string=auth_url.split('tgWebAppData=')[1].split('&tgWebAppVersion')[0]) 141 | 142 | return query 143 | 144 | except: 145 | return None 146 | -------------------------------------------------------------------------------- /utils/starter.py: -------------------------------------------------------------------------------- 1 | import random 2 | from utils.dogs import DogsHouse 3 | from data import config 4 | from utils.core import logger 5 | import datetime 6 | import pandas as pd 7 | from utils.core.telegram import Accounts 8 | import asyncio 9 | import os 10 | 11 | 12 | async def start(thread: int, session_name: str, phone_number: str, proxy: [str, None]): 13 | dogs = DogsHouse(session_name=session_name, phone_number=phone_number, thread=thread, proxy=proxy) 14 | account = session_name + '.session' 15 | try: 16 | balance, age = await dogs.login() 17 | logger.success(f'Thread {thread} | {account} | Account age: {age}; Balance: {balance}') 18 | 19 | if await dogs.first_visit(): 20 | if await dogs.set_first_visit(): 21 | logger.success(f'Thread {thread} | {account} | Set first visit') 22 | await asyncio.sleep(random.uniform(*config.DELAYS['FIRST_VISIT'])) 23 | 24 | current_day = await dogs.get_calendar() 25 | if current_day: 26 | day = current_day['ID'] 27 | 28 | if current_day['IsChecked']: 29 | logger.info(f'Thread {thread} | {account} | Already checked day: {day}') 30 | else: 31 | if await dogs.check_calendar(day): 32 | logger.success(f'Thread {thread} | {account} | Checked day: {day}') 33 | 34 | time_to_sleep = await dogs.timer() + random.uniform(*config.DELAYS['ADDITION_TIME']) 35 | logger.info(f"Thread {thread} | {account} | Sleep {round(time_to_sleep, 1)} seconds to next check") 36 | await asyncio.sleep(time_to_sleep) 37 | 38 | except Exception as e: 39 | logger.error(f'Thread {thread} | {account} | Error: {e}') 40 | 41 | finally: 42 | logger.info(f"Thread {thread} | {account} | End work.") 43 | await dogs.logout() 44 | 45 | async def stats(): 46 | accounts = await Accounts().get_accounts() 47 | 48 | tasks = [] 49 | for thread, account in enumerate(accounts): 50 | session_name, phone_number, proxy = account.values() 51 | tasks.append(asyncio.create_task(DogsHouse(session_name=session_name, phone_number=phone_number, thread=thread, proxy=proxy).stats())) 52 | 53 | data = await asyncio.gather(*tasks) 54 | 55 | path = f"statistics/statistics_{datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}.csv" 56 | columns = ['Phone number', 'Name', 'Balance', 'Leaderboard', 'Age', 'Streak', 'Referrals', 'Referral link', 'Connected wallet', 'Proxy (login:password@ip:port)'] 57 | 58 | if not os.path.exists('statistics'): os.mkdir('statistics') 59 | df = pd.DataFrame(data, columns=columns) 60 | df.to_csv(path, index=False, encoding='utf-8-sig') 61 | 62 | logger.success(f"Saved statistics to {path}") 63 | --------------------------------------------------------------------------------