diff --git a/requirements.txt b/requirements.txt index bcd6212..5ce5e0f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ # requirements.txt +loguru aiohttp==3.9.0b0 -aiogram Telethon-Mod #aiosqlite asyncio diff --git a/run b/run new file mode 100755 index 0000000..b011b80 --- /dev/null +++ b/run @@ -0,0 +1,6 @@ +#!/bin/sh +if [ -d "venv" ]; then + . venv/bin/activate && python3 ubot.py +else + python3 ubot.py +fi diff --git a/ubot.py b/ubot.py index 069eeeb..4ab05ea 100644 --- a/ubot.py +++ b/ubot.py @@ -8,6 +8,7 @@ from telethon import TelegramClient, events, utils from telethon import functions, types import sys +import os import json import re import random @@ -23,10 +24,55 @@ from collections import Counter logger.remove() logger.level("DEBUG", color='') logger.add(sys.stderr, level="DEBUG") +is_termux = os.environ.get('TERMUX_APP__PACKAGE_NAME') +if is_termux: + logger.info('Termux detected, checking permissions...') + logger.info('If you want prevent killing termux by android, get wake lock: check your notifications, find termux app and press "ACQUIRE WAKELOCK"') + logger.warning('This can cause battery drain!') + if os.environ.get('TERMUX_APP__APK_RELEASE') not in ('F_DROID', 'GITHUB'): + logger.warning('You use not f-droid/github apk release, it may have problems...') + logger.warning('F-droid termux release here: https://f-droid.org/en/packages/com.termux/') + logger.warning('Github termux release here: https://github.com/termux/termux-app/releases') + if int(os.environ.get('TERMUX_APP__APP_VERSION_CODE')) < 118: + logger.warning('You use old version of termux, highly recommended that you update to v0.118.0 or higher ASAP for various bug fixes, including a critical world-readable vulnerability') + if os.access('/sdcard', os.W_OK): + logger.success('permission to write on internal storage allowed') + else: + logger.warning('permission denied to write on internal storage') + logger.info('trying get permission...') + os.system('termux-setup-storage') + logger.info('Restart termux [Press CTRL+D or command "exit"]') + sys.exit(0) # Название сессии sessdb = 'tl-ub' -with open("config.json", "r") as configfile: +default_directory = '' +default_config_file_path = 'config.json' +treat_as_true = ('true', '1', 't', 'y', 'yes', 'yeah', 'yup', 'certainly', 'uh-huh') +if is_termux: + default_directory = '/sdcard/ub4tg' + os.system(f'mkdir -p {default_directory}') + default_config_file_path = f'{default_directory}/config.json' +if not os.path.exists(default_config_file_path): + logger.info('config not found, first launch setup...') + api_id = int(input('enter api_id from https://my.telegram.org/ : ')) + api_hash = input('enter api_hash from https://my.telegram.org/ : ') + timezone = input('enter timezone, format is Country/City: ') + db_pymysql = False + db_sqlite3 = True + a_h = input('enable automatic use medkit? [y/n]: ').lower() in treat_as_true + a_404_patient = input('enable automatic bioeb if victim not found or expired? It will be trigger on "Жертва не найдена" [y/n]: ').lower() in treat_as_true + new_config = {'api_id': api_id, + 'api_hash': api_hash, + 'timezone': timezone, + 'db_pymysql': db_pymysql, + 'db_sqlite3': db_sqlite3, + 'a_h': a_h, + 'a_404_patient': a_404_patient} + with open(default_config_file_path, "w") as configfile: + json.dump(new_config, configfile, indent=4) + +with open(default_config_file_path, "r") as configfile: from types import SimpleNamespace cnf_dict = json.load(configfile) config = SimpleNamespace(**cnf_dict) @@ -49,7 +95,7 @@ class states: auto_bioeb_min_interval = (0.666, 3.666) # for fast leak pathogen auto_bioeb_max_interval = (71, 121) # waiting for more pathogen # Default strategy mean: you have 4-5 pathogens when auto bioeb is enabled, pathogen overflow reduced - auto_bioeb_stop = False + auto_bioeb_stop = True where_send_check_avocado = None last_sent_bioeb = 0 # for measure time between reply avocado and bioeb last_reply_bioeb_avocado = 0 # same as above @@ -115,7 +161,11 @@ async def main(): con.commit() if db_sqlite3: - conn = sqlite3.connect(f"{my_id}.sqlite") # покласти базу рядом? + logger.debug('sqlite3 database connecting...') + if is_termux: + conn = sqlite3.connect(f"{default_directory}/{my_id}.sqlite") + else: + conn = sqlite3.connect(f"{my_id}.sqlite") # покласти базу рядом? # conn = sqlite3.connect(f"D:\\Misc\\projects\\Python\\ub4tg_db\\{my_id}.sqlite")#Або повністю c = conn.cursor() c.execute('''CREATE TABLE IF NOT EXISTS zarazy ( @@ -136,6 +186,13 @@ async def main(): expr_str VARCHAR NOT NULL DEFAULT 0 )''') conn.commit() + c.execute('''CREATE TABLE IF NOT EXISTS avocado_exclude ( + user_id INTEGER NOT NULL DEFAULT 0 UNIQUE, + reason VARCHAR + )''') + conn.commit() + logger.debug('sqlite3 database initialized') + #################################################################### async def get_id(url): @@ -193,7 +250,7 @@ async def main(): #################################################################### - @client.on(events.NewMessage(pattern='.*йобнув.*|.*подверг(ла)?.*|.*infected.*|.*сикди.*|.*насрал.*|.*за допомогою довіреності.*|.*by authorization infected.*|.*при помощи анонимуса атаковала.*')) + @client.on(events.NewMessage(pattern='.*йобнув.*|.*подверг(ла)?.*|.*infected.*|.*сикди.*|.*насрал.*|.*выебал.*|.*за допомогою довіреності.*|.*by authorization infected.*|.*при помощи анонимуса атаковала.*')) @logger.catch async def podverg_a(event): logger.debug('bio attack detected') @@ -243,6 +300,11 @@ async def main(): default_bioexpr_theme, default_infected_days_theme, default_pathogen_remaining_theme), + # "Сексуальная индустрия" theme + (r'.* выебал.+', + r"кончила ([0-9\.\,k]+)", + r' ещё ([0-9\ ]+) д.*', + default_pathogen_remaining_theme), # UA theme [via trust] (r'.* за допомогою довіреності зазнала зараження.+', r"([0-9\.\,k]+) біо-ресурса", @@ -266,6 +328,7 @@ async def main(): ) if m.sender_id != 6333102398: + logger.debug('not avocado infection, skipping') pass elif len(m.entities) > 1: h = utils.sanitize_parse_mode( @@ -286,6 +349,7 @@ async def main(): u2url = r[0][1] u1id = await get_id(u1url) u2id = await get_id(u2url) + bio_excludes = [x[0] for x in c.execute('select user_id from avocado_exclude').fetchall()] # print(f'{u1url} [@{u1id}] подверг(ла) {u2url} [@{u2id}]')#показать when = int(datetime.timestamp(m.date)) days = int(re.findall(bio_attack_themes[trying_theme_index][2], t)[ @@ -331,7 +395,7 @@ async def main(): except Exception as Err: logger.exception(f'err: {Err} avocado') states.last_reply_bioeb_avocado = time.time() - if db_sqlite3 and u1id != my_id: + if db_sqlite3 and u1id != my_id and u2id not in bio_excludes: try: c.execute("INSERT INTO avocado(user_id,when_int,bio_str,bio_int,expr_int) VALUES (?, ?, ?, ?, ?)", ( int(u2id), int(when), str(experience), int(exp_int), 0)) @@ -371,11 +435,16 @@ async def main(): else: logger.info( f'''{u1url} [@{u1id}] подверг(ла) {u2url} [@{u2id}] +{experience}, d: {days}''') + if u2id in bio_excludes: + logger.debug(f'{u2id} not added: excluded') #################################################################### @client.on(events.NewMessage(outgoing=True, pattern=r'\.biofuck$')) async def cmd_bf(event): # крч акуратно з цим,вдруг шо я нічо + if states.auto_bioeb_stop is False: + await event.edit('biofucking already runned!') + return m = event.message when = int(datetime.timestamp(m.date)) msg = '🤷' # якщо нема кого то жри рандом. @@ -383,9 +452,15 @@ async def main(): def get_some_patients(limit=1000): count = int(c.execute( f"SELECT COUNT(*) FROM `avocado` WHERE expr_int <= {when} ORDER BY expr_int,when_int ASC LIMIT {limit}").fetchone()[0]) - c.execute( - f"SELECT * FROM `avocado` WHERE expr_int <= {when} ORDER BY expr_int,when_int ASC LIMIT {limit}") - return count, list(c.fetchall()) + patients = list(c.execute( + f"SELECT * FROM `avocado` WHERE expr_int <= {when} ORDER BY expr_int,when_int ASC LIMIT {limit}").fetchall()) + bio_excludes = [x[0] for x in c.execute('select user_id from avocado_exclude').fetchall()] + for p in patients: + if p[0] in bio_excludes: + logger.warning(f'skipping patient {p[0]}, excluded from bioebinng') + patients.remove(p) + + return count, patients count, e_info = get_some_patients() # more random for random and reduce risk get very immun target after restart @@ -452,6 +527,170 @@ async def main(): states.auto_bioeb_stop = True await event.edit('Trying stop...') # ред + @client.on(events.NewMessage(outgoing=True, pattern=r'\.bioexclude')) + async def add_bioeb_exclude(event): + reason = event.text.split(' ', 1)[1] or None + reply = await client.get_messages(event.peer_id, ids=event.reply_to.reply_to_msg_id) + if not reply.entities: + await event.edit('ids not found') + return + t = reply.raw_text + h = utils.sanitize_parse_mode( + 'html').unparse(t, reply.entities) # HTML + r = re.findall(r'', h) + insertion_status = [] + for link in r: + user_id = await get_id(link) + try: + c.execute("INSERT INTO avocado_exclude(user_id, reason) VALUES (?, ?)", (user_id, reason)) + insertion_status.append(f'{user_id}: ok') + except: + insertion_status.append(f'{user_id}: exists') + conn.commit() + insertion_status = '\n'.join(insertion_status) + await event.edit(f'{insertion_status}\nreason: {reason}') + + @client.on(events.NewMessage(outgoing=True, pattern=r'\.bioebmass$')) + async def bioeb_mass(event): + reply = await client.get_messages(event.peer_id, ids=event.reply_to.reply_to_msg_id) + when = int(datetime.timestamp(event.date)) + t = reply.raw_text + h = utils.sanitize_parse_mode( + 'html').unparse(t, reply.entities) # HTML + r_as_list = [] + r = re.findall(r'|(@\d+)', h) + for x in r: + r_as_list.extend(x) + r = r_as_list + + if r == []: + await event.edit('nothing to do: ids not found') + return + + def filter_bioeb(victims_ids): + bio_excludes = [x[0] for x in c.execute('SELECT user_id FROM avocado_exclude').fetchall()] + filted_victims = [] + for v in victims_ids: + if v in bio_excludes: + logger.warning(f'skipping patient {v}, excluded from bioebinng') + elif c.execute(f'SELECT user_id FROM avocado WHERE expr_int >= {when} and user_id == {v}').fetchone(): + logger.warning(f'skipping patient {v}, already eaten') + else: + filted_victims.append(v) + + return list(set(filted_victims)) + bioebbing_ids = [] + for i in r: + if i == '': + continue + if i.startswith('@'): + bioebbing_ids.append(int(i.replace('@', ''))) + else: + bioebbing_ids.append(await get_id(i)) + bioebbing_ids = filter_bioeb(bioebbing_ids) + bioebbing_len = len(bioebbing_ids) + if bioebbing_len == 0: + await event.edit('already eaten or excluded') + return + await event.edit(f'trying eat {bioebbing_len} patients...') + for patient in bioebbing_ids: + await asyncio.sleep(random.uniform(1.234, 4.222)) + await event.respond(f'биоеб {patient}') + + @client.on(events.NewMessage(outgoing=True, pattern=r'\.biostealbackup')) + async def bio_steal_backup(event): + cmd = event.text.split(' ', 1) + if len(cmd) > 1: + cmd = cmd[1].lower() + if cmd == 'me': + logger.info('Requested steal yourself backup...') + else: + logger.info('Stealing backup...') + reply = await client.get_messages(event.peer_id, ids=event.reply_to.reply_to_msg_id) + await event.edit('Downloading file...') + file_path = await reply.download_media(file=f"{default_directory}") + logger.success(f'backup file saved to {file_path}') + victims = None + raw_victims = None + file_format = None + with open(file_path, 'r') as stealed_backup: + if file_path.lower().endswith('.json'): + victims = json.load(stealed_backup) + file_format = 'json' + await event.edit('Processing json victims...') + elif file_path.lower().endswith('.txt'): + raw_victims = stealed_backup.readlines() + file_format = 'txt' + await event.edit('Processing raw txt victims...') + else: + await event.edit('Format not supported, avalaible: txt, json') + return + + added = 0 + rejected = 0 + my_victims_ids = [] + if file_format == 'json': + for v in victims: + user_id = int(v['user_id']) + profit = v['profit'] + when = v['from_infect'] + expr = v['until_infect'] + if cmd == 'me': + my_victims_ids.append(user_id) + c.execute("INSERT OR REPLACE INTO avocado(user_id,when_int,bio_str,bio_int,expr_int) VALUES (?, ?, ?, ?, ?)", + (int(user_id), int(when), str(profit), int(profit), int(expr))) + added += 1 + else: + if not c.execute(f'SELECT user_id FROM avocado WHERE user_id == {user_id}').fetchone() and not c.execute(f'SELECT user_id FROM avocado_exclude WHERE user_id == {user_id}').fetchone(): + c.execute("INSERT INTO avocado(user_id,when_int,bio_str,bio_int,expr_int) VALUES (?, ?, ?, ?, ?)", + (int(user_id), int(when), str(profit), int(profit), 0)) + added += 1 + else: + rejected += 1 + elif file_format == 'txt': + when = int(datetime.timestamp(event.date)) + for raw_v in raw_victims: + if raw_v == '': + continue + user_id = re.findall(r'tg://openmessage\?user_id=(\d+)', raw_v) + if not user_id: + continue + user_id = int(user_id[0]) + profit = re.findall(r'([0-9\.\,k]+) опыта', raw_v) + if not profit: + continue + profit = profit[0] + if ',' in profit: + profit = re.sub(r',', r'.', profit) + if 'k' in profit: + profit_int = int( + float(re.sub('k', '', profit)) * 1000) + else: + profit_int = int(profit) + if not c.execute(f'SELECT user_id FROM avocado WHERE user_id == {user_id}').fetchone() and not c.execute(f'SELECT user_id FROM avocado_exclude WHERE user_id == {user_id}').fetchone(): + c.execute("INSERT INTO avocado(user_id,when_int,bio_str,bio_int,expr_int) VALUES (?, ?, ?, ?, ?)", + (int(user_id), int(when), str(profit), int(profit_int), 0)) + added += 1 + logger.debug(f'added {user_id} - {profit_int}') + else: + rejected += 1 + conn.commit() + logger.success('backup success stealed') + if cmd == 'me': + my_victims_ids = tuple(my_victims_ids) + result = c.execute(f'UPDATE avocado SET expr_int = 0 WHERE user_id NOT IN {my_victims_ids}').fetchall() + conn.commit() + logger.success('database rebased') + del my_victims_ids + del victims # free memory + del raw_victims + if cmd == 'me': + rebased = len(result) + await event.edit(f'Success added/updated {added} patients\nOther {rebased} patients reset to 0') + del result + else: + await event.edit(f'Success added {added} new patients\nRejected or exists: {rejected}') + @client.on(events.NewMessage(outgoing=True, pattern=r'\.biocheck$')) async def set_default_check_chat(event): states.where_send_check_avocado = event.peer_id @@ -483,7 +722,7 @@ async def main(): #################################################################### - @client.on(events.NewMessage(pattern='🚫 Жертва не найдена')) + @client.on(events.NewMessage(pattern='⏱?🚫 Жертва')) async def infection_not_found(event): m = event.message if m.sender_id != 6333102398: