forked from WeebZoneIndia/sukuinote
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit f578c30
Showing
27 changed files
with
1,823 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
__pycache__/ | ||
sessions/ | ||
config.yaml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
telegram: | ||
api_id: 0 | ||
api_hash: https://my.telegram.org | ||
slave_bot_token: https://t.me/BotFather | ||
config: | ||
prefixes: | ||
- . | ||
sessions: | ||
- blankie | ||
- knees | ||
- nezuko | ||
log_chat: -1001278205033 | ||
spamwatch_api: https://t.me/SpamWatchBot | ||
log_user_joins: false | ||
log_user_adds: true | ||
log_reports: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
pyrogram | ||
tgcrypto | ||
requests | ||
aiohttp | ||
PyYAML |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
import os | ||
import html | ||
import time | ||
import logging | ||
import asyncio | ||
import traceback | ||
import functools | ||
import yaml | ||
import aiohttp | ||
from datetime import timedelta | ||
from pyrogram import Client, StopPropagation, ContinuePropagation | ||
from pyrogram.types import Chat, User | ||
from pyrogram.parser import parser | ||
from pyrogram.errors.exceptions.bad_request_400 import PeerIdInvalid, ChannelInvalid | ||
|
||
logging.basicConfig(level=logging.INFO) | ||
with open('config.yaml') as config: | ||
config = yaml.safe_load(config) | ||
loop = asyncio.get_event_loop() | ||
help_dict = dict() | ||
|
||
apps = [] | ||
app_user_ids = dict() | ||
# this code here exists because i can't be fucked | ||
class Parser(parser.Parser): | ||
async def parse(self, text, mode): | ||
if mode == 'through': | ||
return text | ||
return await super().parse(text, mode) | ||
for session_name in config['config']['sessions']: | ||
app = Client(session_name, api_id=config['telegram']['api_id'], api_hash=config['telegram']['api_hash'], plugins={'root': os.path.join(__package__, 'plugins')}, parse_mode='html', workdir='sessions') | ||
app.parser = Parser(app) | ||
apps.append(app) | ||
slave = Client('sukuinote-slave', api_id=config['telegram']['api_id'], api_hash=config['telegram']['api_hash'], plugins={'root': os.path.join(__package__, 'slave-plugins')}, parse_mode='html', bot_token=config['telegram']['slave_bot_token'], workdir='sessions') | ||
slave.parser = Parser(slave) | ||
session = aiohttp.ClientSession() | ||
|
||
async def get_entity(client, entity): | ||
entity_client = client | ||
if not isinstance(entity, Chat): | ||
try: | ||
entity = int(entity) | ||
except ValueError: | ||
pass | ||
except TypeError: | ||
entity = entity.id | ||
try: | ||
entity = await client.get_chat(entity) | ||
except (PeerIdInvalid, ChannelInvalid): | ||
for app in apps: | ||
if app != client: | ||
try: | ||
entity = await app.get_chat(entity) | ||
except (PeerIdInvalid, ChannelInvalid): | ||
pass | ||
else: | ||
entity_client = app | ||
break | ||
else: | ||
entity = await slave.get_chat(entity) | ||
entity_client = slave | ||
return entity, entity_client | ||
|
||
async def get_user(client, entity): | ||
entity_client = client | ||
if not isinstance(entity, User): | ||
try: | ||
entity = int(entity) | ||
except ValueError: | ||
pass | ||
except TypeError: | ||
entity = entity.id | ||
try: | ||
entity = await client.get_users(entity) | ||
except PeerIdInvalid: | ||
for app in apps: | ||
if app != client: | ||
try: | ||
entity = await app.get_users(entity) | ||
except PeerIdInvalid: | ||
pass | ||
else: | ||
entity_client = app | ||
break | ||
else: | ||
entity = await slave.get_users(entity) | ||
entity_client = slave | ||
return entity, entity_client | ||
|
||
def log_errors(func): | ||
@functools.wraps(func) | ||
async def wrapper(client, *args): | ||
try: | ||
await func(client, *args) | ||
except (StopPropagation, ContinuePropagation): | ||
raise | ||
except Exception: | ||
tb = traceback.format_exc() | ||
try: | ||
await slave.send_message(config['config']['log_chat'], f'Exception occured in {func.__name__}\n\n{tb}', parse_mode=None) | ||
except Exception: | ||
logging.exception('Failed to log exception for %s as slave', func.__name__) | ||
tb = traceback.format_exc() | ||
for app in apps: | ||
try: | ||
await app.send_message(config['config']['log_chat'], f'Exception occured in {func.__name__}\n\n{tb}', parse_mode=None) | ||
except Exception: | ||
logging.exception('Failed to log exception for %s as app', func.__name__) | ||
tb = traceback.format_exc() | ||
else: | ||
break | ||
raise | ||
raise | ||
return wrapper | ||
|
||
def public_log_errors(func): | ||
@functools.wraps(func) | ||
async def wrapper(client, message): | ||
try: | ||
await func(client, message) | ||
except (StopPropagation, ContinuePropagation): | ||
raise | ||
except Exception: | ||
await message.reply_text(traceback.format_exc(), parse_mode=None) | ||
raise | ||
return wrapper | ||
|
||
# https://stackoverflow.com/a/49361727 | ||
def format_bytes(size): | ||
size = int(size) | ||
# 2**10 = 1024 | ||
power = 1000 | ||
n = 0 | ||
power_labels = {0 : '', 1: 'K', 2: 'M', 3: 'G', 4: 'T'} | ||
while size > power: | ||
size /= power | ||
n += 1 | ||
return f"{size:.2f} {power_labels[n]+'B'}" | ||
|
||
# https://stackoverflow.com/a/34325723 | ||
def return_progress_string(current, total): | ||
filled_length = int(30 * current // total) | ||
return '[' + '=' * filled_length + ' ' * (30 - filled_length) + ']' | ||
|
||
# https://stackoverflow.com/a/852718 | ||
# https://stackoverflow.com/a/775095 | ||
def calculate_eta(current, total, start_time): | ||
if not current: | ||
return '00:00:00' | ||
end_time = time.time() | ||
elapsed_time = end_time - start_time | ||
seconds = (elapsed_time * (total / current)) - elapsed_time | ||
thing = ''.join(str(timedelta(seconds=seconds)).split('.')[:-1]).split(', ') | ||
thing[-1] = thing[-1].rjust(8, '0') | ||
return ', '.join(thing) | ||
|
||
progress_callback_data = dict() | ||
async def progress_callback(current, total, reply, text, upload): | ||
message_identifier = (reply.chat.id, reply.message_id) | ||
last_edit_time, prevtext, start_time = progress_callback_data.get(message_identifier, (0, None, time.time())) | ||
if current == total: | ||
try: | ||
progress_callback_data.pop(message_identifier) | ||
except KeyError: | ||
pass | ||
elif (time.time() - last_edit_time) > 1: | ||
handle = 'Upload' if upload else 'Download' | ||
if last_edit_time: | ||
speed = format_bytes((total - current) / (time.time() - start_time)) | ||
else: | ||
speed = '0 B' | ||
text = f'''{text} | ||
<code>{return_progress_string(current, total)}</code> | ||
<b>Total Size:</b> {format_bytes(total)} | ||
<b>{handle}ed Size:</b> {format_bytes(current)} | ||
<b>{handle} Speed:</b> {speed}/s | ||
<b>ETA:</b> {calculate_eta(current, total, start_time)}''' | ||
if prevtext != text: | ||
await reply.edit_text(text) | ||
prevtext = text | ||
last_edit_time = time.time() | ||
progress_callback_data[message_identifier] = last_edit_time, prevtext, start_time |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import asyncio | ||
from pyrogram import idle | ||
from . import loop, apps, slave, app_user_ids, session | ||
|
||
async def main(): | ||
async def _start_app(app): | ||
await app.start() | ||
asyncio.create_task(_get_me_loop(app)) | ||
async def _get_me_loop(app): | ||
while True: | ||
try: | ||
me = await app.get_me() | ||
app_user_ids[me.id] = me | ||
except: | ||
pass | ||
await asyncio.sleep(60) | ||
await asyncio.gather(*(_start_app(app) for app in apps), slave.start()) | ||
await idle() | ||
await asyncio.gather(*(app.stop() for app in apps), slave.stop()) | ||
await session.close() | ||
|
||
loop.run_until_complete(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import html | ||
from pyrogram import Client, filters | ||
from .. import config, help_dict, log_errors, public_log_errors, get_entity | ||
|
||
ZWS = '\u200B' | ||
def _generate_sexy(entity, ping): | ||
text = entity.first_name | ||
if entity.last_name: | ||
text += f' {entity.last_name}' | ||
sexy_text = '<code>[DELETED]</code>' if entity.is_deleted else html.escape(text or 'Empty???') | ||
if not entity.is_deleted: | ||
if ping: | ||
sexy_text = f'<a href="tg://user?id={entity.id}">{sexy_text}</a>' | ||
elif entity.username: | ||
sexy_text = f'<a href="https://t.me/{entity.username}">{sexy_text}</a>' | ||
elif not ping: | ||
sexy_text = sexy_text.replace('@', f'@{ZWS}') | ||
if entity.is_bot: | ||
sexy_text += ' <code>[BOT]</code>' | ||
if entity.is_verified: | ||
sexy_text += ' <code>[VERIFIED]</code>' | ||
if entity.is_support: | ||
sexy_text += ' <code>[SUPPORT]</code>' | ||
if entity.is_scam: | ||
sexy_text += ' <code>[SCAM]</code>' | ||
return sexy_text | ||
|
||
@Client.on_message(~filters.sticker & ~filters.via_bot & ~filters.edited & filters.outgoing & filters.command(['admin', 'admins'], prefixes=config['config']['prefixes'])) | ||
@log_errors | ||
@public_log_errors | ||
async def admins(client, message): | ||
chat, entity_client = message.chat, client | ||
command = message.command | ||
command.pop(0) | ||
if command: | ||
chat = ' '.join(command) | ||
try: | ||
chat = int(chat) | ||
except ValueError: | ||
pass | ||
chat, entity_client = await get_entity(client, chat) | ||
text_unping = text_ping = '' | ||
async for i in entity_client.iter_chat_members(chat.id, filter='administrators'): | ||
text_unping += f'\n[<code>{i.user.id}</code>] {_generate_sexy(i.user, False)}' | ||
text_ping += f'\n[<code>{i.user.id}</code>] {_generate_sexy(i.user, True)}' | ||
if i.title: | ||
text_unping += f' // {html.escape(i.title.replace("@", "@" + ZWS))}' | ||
text_ping += f' // {html.escape(i.title)}' | ||
reply = await message.reply_text(text_unping, disable_web_page_preview=True) | ||
await reply.edit_text(text_ping, disable_web_page_preview=True) | ||
|
||
help_dict['admins'] = ('Admins', | ||
'''{prefix}admins <i>[chat]</i> - Lists the admins in <i>[chat]</i> | ||
Aliases: {prefix}admin''') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import html | ||
from pyrogram import Client, filters | ||
from pyrogram.types.messages_and_media import Photo | ||
from pyrogram.errors.exceptions.forbidden_403 import Forbidden | ||
from .. import slave, config, help_dict, log_errors, public_log_errors | ||
|
||
@Client.on_message(~filters.sticker & ~filters.via_bot & ~filters.edited & filters.outgoing & filters.command(['anilist', 'al', 'alc', 'alchar', 'alcharacter', 'anilistc', 'anilistchar', 'anilistcharacter'], prefixes=config['config']['prefixes'])) | ||
@log_errors | ||
@public_log_errors | ||
async def anilist(client, message): | ||
bot = await slave.get_me() | ||
query = message.command | ||
page = 1 | ||
character = 'c' in query.pop(0) | ||
if query and query[0].isnumeric(): | ||
page = int(query.pop(0)) | ||
page -= 1 | ||
if page < 0: | ||
page = 0 | ||
elif page > 9: | ||
page = 9 | ||
query = ' '.join(query) | ||
if not query: | ||
return | ||
results = await client.get_inline_bot_results(bot.username or bot.id, f'al{"c" if character else ""} ' + query) | ||
if not results.results: | ||
await message.reply_text('No results') | ||
return | ||
try: | ||
await message.reply_inline_bot_result(results.query_id, results.results[page].id) | ||
except IndexError: | ||
await message.reply_text(f'There are only {len(results.results)} results') | ||
except Forbidden: | ||
text = {'message': results.results[page].send_message.message, 'entities': results.results[page].send_message.entities} | ||
try: | ||
photo = Photo._parse(client, results.results[page].photo) | ||
await message.reply_cached_media(photo.file_id, photo.file_ref, caption=text, parse_mode='through') | ||
except Forbidden: | ||
await message.reply_text(text, disable_web_page_preview=True, parse_mode='through') | ||
|
||
help_dict['anilist'] = ('Anilist', | ||
'''{prefix}anilist <i><query></i> - Searches for anime/manga named <i><query></i> on Anilist | ||
Aliases: {prefix}al | ||
Can also be activated inline with: @{bot} anilist <i><query></i> or @{bot} al <i><query></i> | ||
{prefix}anilistc <i><query></i> - Searches for characters named <i><query></i> on Anilist | ||
Aliases: {prefix}alc, alchar, alcharacter, anilistchar, anilistcharacter | ||
Can also be activated inline with: @{bot} anilistc <i><query></i> or @{bot} alc <i><query></i>''') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import html | ||
import tempfile | ||
from pyrogram import Client, filters | ||
from .. import config, help_dict, log_errors, session, progress_callback, public_log_errors | ||
|
||
@Client.on_message(~filters.sticker & ~filters.via_bot & ~filters.edited & filters.outgoing & filters.command('cat', prefixes=config['config']['prefixes'])) | ||
@log_errors | ||
@public_log_errors | ||
async def cat(client, message): | ||
media = message.document | ||
if not media and not getattr(message.reply_to_message, 'empty', True): | ||
media = message.reply_to_message.document | ||
if not media: | ||
await message.reply_text('Document required') | ||
return | ||
done = False | ||
with tempfile.NamedTemporaryFile() as file: | ||
reply = await message.reply_text('Downloading...') | ||
await client.download_media(media, file_name=file.name, progress=progress_callback, progress_args=(reply, 'Downloading...', False)) | ||
with open(file.name) as nfile: | ||
while True: | ||
chunk = nfile.read(4096) | ||
if not chunk: | ||
break | ||
chunk = f'<code>{html.escape(chunk)}</code>' | ||
if done: | ||
await message.reply_text(chunk, quote=False) | ||
else: | ||
await reply.edit_text(chunk) | ||
done = True | ||
|
||
help_dict['cat'] = ('cat', '{prefix}cat <i>(as caption of text file or reply)</i> - Outputs file\'s text to Telegram') |
Oops, something went wrong.