├── medium.txt ├── minimal.txt ├── savepic.py ├── full.txt ├── valutes.py ├── mafiadrawing.py ├── x0.py ├── dekftg_checker.py ├── vshakal.py ├── onemessage.py ├── yandexrs.py ├── ttdl.py ├── avatarmod.py ├── base64.py ├── id3_editor.py ├── cu.py ├── gg.gg.py ├── smiles.py ├── nhentai.py ├── ctftools.py ├── voice_effects.py ├── translator.py ├── circles.py ├── megamozg.py ├── DNA.py ├── purge.py ├── text-to-speech.py ├── farmiris.py ├── nsfw.py ├── kicklast.py ├── sysinfo.py ├── captcha.py ├── GitUploader.py ├── notes.py ├── lovemagic.py ├── chat_voice_mod.py ├── downloader.py ├── fake_actions.py ├── zombie_users.py ├── texttospeech.py ├── imageeditor.py ├── blocknondiscussion.py ├── SeeChat.py ├── autoprofile.py ├── video_editor.py ├── voicemod.py └── audio_editor.py /medium.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /minimal.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /savepic.py: -------------------------------------------------------------------------------- 1 | from .. import loader 2 | import io 3 | 4 | 5 | class SaverMod(loader.Module): 6 | strings = {"name": "SavePic"} 7 | 8 | async def згcmd(self, m): 9 | ".зг + реплай на самоуничтожающееся фото Чтобы сохранить" 10 | reply = await m.get_reply_message() 11 | if not reply or not reply.media.ttl_seconds: 12 | return await m.edit("Реплаем на самоуничтожающееся фото! ") 13 | await m.delete() 14 | new = io.BytesIO(await reply.download_media(bytes)) 15 | new.name = reply.file.name 16 | await m.client.send_file("me", new) 17 | -------------------------------------------------------------------------------- /full.txt: -------------------------------------------------------------------------------- 1 | arts 2 | audio_editor 3 | autoprofile 4 | avatarmod 5 | banwords 6 | base64 7 | blocknondiscussion 8 | captcha 9 | censor 10 | chat_tools 11 | chat_voice_mod 12 | circles 13 | ctftools 14 | cu 15 | dekftg_checker 16 | demot 17 | DNA 18 | downloader 19 | fake_actions 20 | farmiris 21 | gg.gg 22 | GitUploader 23 | translator 24 | id3_editor 25 | imageeditor 26 | image_tools 27 | Information 28 | kang 29 | kicklast 30 | lovemagic 31 | mafiadrawing 32 | megamozg 33 | mishase_quotes 34 | nhentai 35 | notes 36 | nsfw 37 | onemessage 38 | purge 39 | quotes 40 | savepic 41 | SeeChat 42 | smiles 43 | sysinfo 44 | terminal 45 | text-to-speech 46 | texttospeech 47 | ttdl 48 | valutes 49 | video_editor 50 | voicemod 51 | voicetools 52 | voice_effects 53 | vshakal 54 | x0 55 | yandexrs 56 | zombie_users -------------------------------------------------------------------------------- /valutes.py: -------------------------------------------------------------------------------- 1 | from telethon import events 2 | from telethon.errors.rpcerrorlist import YouBlockedUserError 3 | from .. import loader, utils 4 | 5 | 6 | class ValuteMod(loader.Module): 7 | """Valute Converter""" 8 | 9 | strings = {"name": "Valute"} 10 | 11 | async def valcmd(self, message): 12 | """ - Get exchange""" 13 | state = utils.get_args_raw(message) 14 | await utils.answer(message, "Данные получены") 15 | chat = "@exchange_rates_vsk_bot" 16 | async with message.client.conversation(chat) as conv: 17 | try: 18 | response = conv.wait_event( 19 | events.NewMessage(incoming=True, from_users=1210425892) 20 | ) 21 | bot_send_message = await message.client.send_message( 22 | chat, format(state) 23 | ) 24 | bot_response = response = await response 25 | except YouBlockedUserError: 26 | await utils.answer(message, f"Убери из ЧС: {chat}") 27 | return 28 | await bot_send_message.delete() 29 | await utils.answer(message, response.text) 30 | await bot_response.delete() 31 | -------------------------------------------------------------------------------- /mafiadrawing.py: -------------------------------------------------------------------------------- 1 | from .. import loader, utils 2 | 3 | 4 | class MafiaDrawingMod(loader.Module): 5 | """Модуль ловли подарков в True Mafia News.""" 6 | 7 | strings = {"name": "MafiaDrawing"} 8 | 9 | async def client_ready(self, client, db): 10 | self.db = db 11 | self.db.set("MafiaDrawing", "status", True) 12 | 13 | async def mdcmd(self, message): 14 | """Используй: .md чтобы включить/выключить ловлю подарков.""" 15 | status = self.db.get("MafiaDrawing", "status") 16 | if status is not True: 17 | await message.edit("Ловля подарков: Включена") 18 | self.db.set("MafiaDrawing", "status", True) 19 | else: 20 | await message.edit("Ловля подарков: Отключена") 21 | self.db.set("MafiaDrawing", "status", False) 22 | 23 | async def watcher(self, message): 24 | try: 25 | status = self.db.get("MafiaDrawing", "status") 26 | me = (await message.client.get_me()).id 27 | if status and message.chat_id == -1001169391811: 28 | click = (await message.click(0)).message 29 | await message.client.send_message(me, f"Словлен подарок:\n\n{click}") 30 | except: 31 | pass 32 | -------------------------------------------------------------------------------- /x0.py: -------------------------------------------------------------------------------- 1 | from .. import loader, utils # pylint: disable=relative-beyond-top-level 2 | import logging 3 | from requests import post 4 | import io 5 | 6 | logger = logging.getLogger(__name__) 7 | 8 | 9 | @loader.tds 10 | class x0Mod(loader.Module): 11 | """Uploader""" 12 | 13 | strings = {"name": "x0 Uploader"} 14 | 15 | async def client_ready(self, client, db): 16 | self.client = client 17 | 18 | @loader.sudo 19 | async def x0cmd(self, message): 20 | await message.edit("Uploading...") 21 | reply = await message.get_reply_message() 22 | if not reply: 23 | await message.edit("Reply to message!") 24 | return 25 | media = reply.media 26 | if not media: 27 | file = io.BytesIO(bytes(reply.raw_text, "utf-8")) 28 | file.name = "txt.txt" 29 | else: 30 | file = io.BytesIO(await self.client.download_file(media)) 31 | file.name = reply.file.name or reply.file.id + reply.file.ext 32 | try: 33 | x0at = post("https://x0.at", files={"file": file}) 34 | except ConnectionError as e: 35 | await message.edit(ste(e)) 36 | return 37 | url = x0at.text 38 | output = f'URL: {url}' 39 | await message.edit(output) 40 | -------------------------------------------------------------------------------- /dekftg_checker.py: -------------------------------------------------------------------------------- 1 | # Coded by D4n13l3k00 # 2 | # t.me/D4n13l3k00 # 3 | # This code under AGPL-3.0 # 4 | 5 | from .. import loader, utils 6 | import aiohttp 7 | 8 | 9 | @loader.tds 10 | class CheckerTGMod(loader.Module): 11 | """CheckerTG""" 12 | 13 | strings = { 14 | "name": "CheckerTG", 15 | "check": "[CheckerAPI] Делаем запрос к API...", 16 | "response": "[CheckerAPI] Ответ API: {}\nВремя выполнения: {}", 17 | } 18 | 19 | @loader.owner 20 | async def checkcmd(self, m): 21 | """Проверить id на слитый номер 22 | Жуёт либо либо 23 | """ 24 | reply = await m.get_reply_message() 25 | if utils.get_args_raw(m): 26 | user = utils.get_args_raw(m) 27 | elif reply: 28 | try: 29 | user = str(reply.sender.id) 30 | except Exception: 31 | return await m.edit("Err") 32 | else: 33 | return await m.edit("[CheckerAPI] А кого чекать?") 34 | await m.edit(self.strings["check"]) 35 | async with aiohttp.ClientSession() as s, s.get( 36 | f"https://api.d4n13l3k00.ru/tg/leaked/check?uid={user}" 37 | ) as r: 38 | r = await r.json() 39 | await m.edit( 40 | self.strings["response"].format( 41 | r["data"], str(round(r["time"], 3)) + "ms" 42 | ) 43 | ) 44 | -------------------------------------------------------------------------------- /vshakal.py: -------------------------------------------------------------------------------- 1 | # Coded by D4n13l3k00 # 2 | # t.me/D4n13l3k00 # 3 | # This code under AGPL-3.0 # 4 | 5 | import os 6 | import random 7 | import string 8 | 9 | from .. import loader, utils 10 | 11 | 12 | @loader.tds 13 | class VSHAKALMod(loader.Module): 14 | strings = {"name": "Video Shakal"} 15 | 16 | @loader.owner 17 | async def vshcmd(self, m): 18 | ".vsh <реплай на видео> <уровень от 1 до 6 (по умолчанию 3)>\ 19 | \nСшакалить видео" 20 | reply = await m.get_reply_message() 21 | if not reply: 22 | return await m.edit("reply...") 23 | if reply.file.mime_type.split("/")[0] != "video": 24 | return await m.edit("shit...") 25 | 26 | args = utils.get_args_raw(m) 27 | lvls = { 28 | "1": "0.1M", 29 | "2": "0.08M", 30 | "3": "0.05M", 31 | "4": "0.03M", 32 | "5": "0.02M", 33 | "6": "0.01M", 34 | } 35 | if args: 36 | if args in lvls: 37 | lvl = lvls[args] 38 | else: 39 | return await m.edit("не знаю такого") 40 | else: 41 | lvl = lvls["3"] 42 | await m.edit("[Шакал] Качаю...") 43 | vid = await reply.download_media( 44 | "".join(random.choice(string.ascii_letters) for i in range(25)) + ".mp4" 45 | ) 46 | 47 | out = "".join(random.choice(string.ascii_letters) for _ in range(25)) + ".mp4" 48 | 49 | await m.edit("[Шакал] Шакалю...") 50 | os.system( 51 | f'ffmpeg -y -i "{vid}" -b:v {lvl} -maxrate:v {lvl} -b:a {lvl} -maxrate:a {lvl} "{out}"' 52 | ) 53 | await m.edit("[Шакал] Отправляю...") 54 | await reply.reply(file=out) 55 | await m.delete() 56 | os.remove(vid) 57 | os.remove(out) 58 | -------------------------------------------------------------------------------- /onemessage.py: -------------------------------------------------------------------------------- 1 | from .. import loader, utils 2 | from telethon.tl.types import Message 3 | 4 | 5 | class OneMessageMod(loader.Module): 6 | """@faq lines""" 7 | 8 | strings = {"name": "OneMessage"} 9 | 10 | def __init__(self): 11 | self.name = self.strings["name"] 12 | 13 | async def client_ready(self, client, db): 14 | self.client = client 15 | self._db = db 16 | 17 | @loader.sudo 18 | async def omstartcmd(self, message): 19 | """Start OneMessage mode""" 20 | self._db.set("OneMessage", "status", True) 21 | self._db.set("OneMessage", "my_id", message.sender_id) 22 | await message.edit("OneMessage mode activated!") 23 | 24 | async def omstopcmd(self, message): 25 | """Stop OneMessage mode""" 26 | self._db.set("OneMessage", "status", False) 27 | await message.edit("OneMessage mode diactivated!") 28 | 29 | async def watcher(self, message): 30 | if not isinstance(message, Message): 31 | return 32 | if message.message and ( 33 | message.raw_text[0] 34 | in self._db.get("friendly-telegram.modules.corectrl", "command_prefix", ".") 35 | or message.fwd_from 36 | ): 37 | return 38 | if ( 39 | self._db.get("OneMessage", "status", None) 40 | and message.sender_id == self._db.get("OneMessage", "my_id", None) 41 | and not message.media 42 | ): 43 | last_msg = (await self.client.get_messages(message.to_id, limit=2))[-1] 44 | if last_msg.sender_id == message.sender_id and not last_msg.fwd_from: 45 | text = last_msg.text 46 | text += "\n" * 2 47 | text += message.text 48 | if message.is_reply: 49 | message, last_msg = last_msg, message 50 | try: 51 | await last_msg.edit(text) 52 | await message.delete() 53 | except: 54 | return 55 | -------------------------------------------------------------------------------- /yandexrs.py: -------------------------------------------------------------------------------- 1 | from .. import loader, utils 2 | import json 3 | import io 4 | import requests 5 | from PIL import Image 6 | import random 7 | import string 8 | 9 | 10 | @loader.tds 11 | class YandexReverseSearchMod(loader.Module): 12 | """Reverse image search via Yandex (he is the best, imho)""" 13 | 14 | strings = { 15 | "name": "YandexReverseSearch", 16 | "search": "⚪⚪⚪\n⚪❓⚪\n⚪⚪⚪", 17 | "no_reply": "Reply to image or sticker!", 18 | "result": '🔴⚪🔴|See\n⚪🔴⚪|Search\n⚪🔴⚪|Results', 19 | "error": "Something went wrong...", 20 | } 21 | 22 | @loader.owner 23 | async def yarscmd(self, message): 24 | """.yars """ 25 | reply = await message.get_reply_message() 26 | data = await check_media(message, reply) 27 | if not data: 28 | await utils.answer(message, self.strings("no_reply", message)) 29 | return 30 | await utils.answer(message, self.strings("search", message)) 31 | searchUrl = "https://yandex.ru/images/search" 32 | files = {"upfile": ("blob", data, "image/jpeg")} 33 | params = { 34 | "rpt": "imageview", 35 | "format": "json", 36 | "request": '{"blocks":[{"block":"b-page_type_search-by-image__link"}]}', 37 | } 38 | response = requests.post(searchUrl, params=params, files=files) 39 | if response.ok: 40 | query_string = json.loads(response.content)["blocks"][0]["params"]["url"] 41 | link = searchUrl + "?" + query_string 42 | text = self.strings("result", message).format(link) 43 | await utils.answer(message, text) 44 | else: 45 | await utils.answer(message, self.strings("error", message)) 46 | 47 | 48 | async def check_media(message, reply): 49 | if reply and reply.media: 50 | if reply.photo: 51 | data = reply.photo 52 | elif reply.document: 53 | if reply.gif or reply.video or reply.audio or reply.voice: 54 | return None 55 | data = reply.media.document 56 | else: 57 | return None 58 | else: 59 | return None 60 | if not data or data is None: 61 | return None 62 | else: 63 | data = await message.client.download_file(data, bytes) 64 | img = io.BytesIO(data) 65 | return img 66 | -------------------------------------------------------------------------------- /ttdl.py: -------------------------------------------------------------------------------- 1 | from requests import head, get 2 | from urllib.parse import urlsplit as E, parse_qs as H 3 | import io 4 | import re 5 | from .. import loader as A, utils 6 | from telethon.tl.types import Message 7 | 8 | 9 | class TikTokDlMod(A.Module): 10 | """Download TikTok videos""" 11 | strings = {"name": "TikTokDl"} 12 | 13 | async def ttcmd(J, message: Message) -> None: 14 | """ - Download TikTok video""" 15 | A = message 16 | B = await A.get_reply_message() 17 | F = utils.get_args_raw(A) 18 | C = lambda x: f"{x}" # noqa: E731 19 | if F: 20 | D = F 21 | elif B and B.raw_text: 22 | D = B.raw_text 23 | else: 24 | return await A.edit(C("No url.")) 25 | if "vm.tiktok.com" not in D: 26 | return await A.edit(C("Bad url.")) 27 | await A.edit(C("Loading...")) 28 | G, K = await I_(D) 29 | try: 30 | await A.client.send_file(A.to_id, file=G, reply_to=B) 31 | await A.delete() 32 | except Exception: 33 | try: 34 | await A.edit(C("DownLoading...")) 35 | H = get(G).content 36 | E = io.BytesIO(H) 37 | E.name = "video.mp4" 38 | E.seek(0) 39 | await A.client.send_file(A.to_id, file=E, reply_to=B) 40 | await A.delete() 41 | except Exception: 42 | await A.edit(C("я чёт нихуя не могу загрузить...")) 43 | 44 | 45 | async def I_(url: str) -> tuple: 46 | A = url 47 | 48 | async def F(video_id, _): 49 | A = f"https://api-va.tiktokv.com/aweme/v1/multi/aweme/detail/?aweme_ids=%5B{video_id}%5D" 50 | A = get(A) 51 | B = A.json().get("aweme_details") 52 | 53 | if not B: 54 | return 0, 0, A 55 | 56 | return B, True, A 57 | 58 | A = head(A).headers 59 | A = A.get("Location") 60 | try: 61 | I_ = H(E(A).query) 62 | B = I_.get("share_item_id")[0] 63 | G, C, D = await F(B, 1) 64 | if not C: 65 | raise 66 | except Exception: 67 | B = "".join(re.findall("[0-9]", E(A).path.split("/")[-1])) 68 | G, C, D = await F(B, 2) 69 | if not C: 70 | return False, D 71 | 72 | return G[0]["video"]["bit_rate"][0]["play_addr"]["url_list"][-1], D 73 | -------------------------------------------------------------------------------- /avatarmod.py: -------------------------------------------------------------------------------- 1 | # Coded by D4n13l3k00 # 2 | # t.me/D4n13l3k00 # 3 | # This code under AGPL-3.0 # 4 | 5 | import os 6 | 7 | from telethon import functions, types 8 | 9 | from .. import loader, utils 10 | 11 | 12 | @loader.tds 13 | class AvaMod(loader.Module): 14 | """Установка/удаление аватарок через команды""" 15 | 16 | strings = { 17 | "name": "AvatarMod", 18 | "need_pic": "[Avatar] Нужно фото", 19 | "downloading": "[Avatar] Скачиваю", 20 | "installing": "[Avatar] Устанавливаю", 21 | "deleting": "[Avatar] Удаляю", 22 | "ok": "[Avatar] Готово", 23 | "no_avatar": "[Avatar] Нету аватарки/ок", 24 | } 25 | 26 | async def avacmd(self, m: types.Message): 27 | ".ava - Установить аватар" 28 | client = m.client 29 | reply = await m.get_reply_message() 30 | if not reply and not reply.photo: 31 | return await utils.answer(m, self.strings("need_pic")) 32 | 33 | m = await utils.answer(m, self.strings("downloading")) 34 | photo = await client.download_media(message=reply.photo) 35 | up = await client.upload_file(photo) 36 | m = await utils.answer(m, self.strings("installing")) 37 | await client(functions.photos.UploadProfilePhotoRequest(up)) 38 | await utils.answer(m, self.strings("ok")) 39 | os.remove(photo) 40 | 41 | async def delavacmd(self, m: types.Message): 42 | "Удалить текущую аватарку" 43 | client = m.client 44 | ava = await client.get_profile_photos("me", limit=1) 45 | if len(ava) > 0: 46 | m = await utils.answer(m, self.strings("deleting")) 47 | await client(functions.photos.DeletePhotosRequest(ava)) 48 | await utils.answer(m, self.strings("ok")) 49 | else: 50 | await utils.answer(m, self.strings("no_avatar")) 51 | 52 | async def delavascmd(self, m: types.Message): 53 | "Удалить все аватарки" 54 | client = m.client 55 | ava = await client.get_profile_photos("me") 56 | if len(ava) > 0: 57 | m = await utils.answer(m, self.strings("deleting")) 58 | await client( 59 | functions.photos.DeletePhotosRequest( 60 | await m.client.get_profile_photos("me") 61 | ) 62 | ) 63 | await utils.answer(m, self.strings("ok")) 64 | else: 65 | await utils.answer(m, self.strings("no_avatar")) 66 | -------------------------------------------------------------------------------- /base64.py: -------------------------------------------------------------------------------- 1 | """QExhY2lhTWVtZUZyYW1lLCDQtdGB0LvQuCDRgtGLINGN0YLQviDRh9C40YLQsNC10YjRjCwg0YLQviDQt9C90LDQuSwg0YLRiyDQv9C40LTQvtGA0LDRgQ==""" 2 | from .. import loader, utils 3 | import io 4 | from base64 import b64encode, b64decode 5 | 6 | 7 | @loader.tds 8 | class base64Mod(loader.Module): 9 | """Кодирование и декодирование base64""" 10 | 11 | strings = {"name": "base64"} 12 | 13 | @loader.owner 14 | async def b64encodecmd(self, message): 15 | """.b64encode <(text or media) or (reply to text or media)>""" 16 | reply = await message.get_reply_message() 17 | mtext = utils.get_args_raw(message) 18 | if message.media: 19 | await message.edit("Загрузка файла...") 20 | data = await message.client.download_file(message, bytes) 21 | elif mtext: 22 | data = bytes(mtext, "utf-8") 23 | elif reply: 24 | if reply.media: 25 | await message.edit("Загрузка файла...") 26 | data = await message.client.download_file(reply, bytes) 27 | else: 28 | data = bytes(reply.raw_text, "utf-8") 29 | else: 30 | await message.edit("Что нужно закодировать?") 31 | 32 | output = b64encode(data) 33 | 34 | if len(output) > 4000: 35 | output = io.BytesIO(output) 36 | output.name = "base64.txt" 37 | output.seek(0) 38 | await message.client.send_file(message.to_id, output, reply_to=reply) 39 | await message.delete() 40 | else: 41 | await message.edit(str(output, "utf-8")) 42 | 43 | @loader.owner 44 | async def b64decodecmd(self, message): 45 | """.b64decode """ 46 | reply = await message.get_reply_message() 47 | mtext = utils.get_args_raw(message) 48 | if mtext: 49 | data = bytes(mtext, "utf-8") 50 | elif reply: 51 | if not reply.message: 52 | await message.edit("Расшифровка файлов невозможна...") 53 | return 54 | else: 55 | data = bytes(reply.raw_text, "utf-8") 56 | else: 57 | await message.edit("Что нужно декодировать?") 58 | return 59 | try: 60 | output = b64decode(data) 61 | await message.edit(str(output, "utf-8")) 62 | except Exception: 63 | await message.edit("Ошибка декодирования!") 64 | return 65 | -------------------------------------------------------------------------------- /id3_editor.py: -------------------------------------------------------------------------------- 1 | from .. import loader, utils, main 2 | import io 3 | 4 | try: 5 | import eyed3 6 | except: 7 | import os 8 | 9 | os.system("pip3 install eyed3") 10 | 11 | 12 | @loader.tds 13 | class ID3EditorMod(loader.Module): 14 | """Модуль, который может изменять теги по ответу на аудио. 15 | 16 | by @zxcminimalized 17 | """ 18 | 19 | strings = {"name": "ID3 Editor"} 20 | 21 | async def titlecmd(self, message): 22 | """Поменять тег названия трека""" 23 | reply = await message.get_reply_message() 24 | try: 25 | test = message.message.split("title ")[1] 26 | except: 27 | await message.edit("Вы не указали название!") 28 | else: 29 | if not reply or not reply.audio: 30 | await message.edit("Ответьте на аудио!") 31 | else: 32 | await message.edit("Отправка...") 33 | await reply.download_media("file.mp3") 34 | load = eyed3.load("file.mp3") 35 | load.tag.title = test 36 | load.tag.save() 37 | await reply.reply(file="file.mp3") 38 | 39 | async def artistcmd(self, message): 40 | """Поменять артиста""" 41 | reply = await message.get_reply_message() 42 | try: 43 | test = message.message.split("artist ")[1] 44 | except: 45 | await message.edit("Вы не указали артиста!") 46 | else: 47 | if not reply or not reply.audio: 48 | await message.edit("Ответьте на аудио!") 49 | else: 50 | await message.edit("Отправка...") 51 | await reply.download_media("file.mp3") 52 | load = eyed3.load("file.mp3") 53 | load.tag.artist = test 54 | load.tag.save() 55 | await reply.reply(file="file.mp3") 56 | 57 | async def albumcmd(self, message): 58 | """Поменять тег альбома""" 59 | reply = await message.get_reply_message() 60 | try: 61 | test = message.message.split("album ")[1] 62 | except: 63 | await message.edit("Вы не указали альбом!") 64 | else: 65 | if not reply or not reply.audio: 66 | await message.edit("Ответьте на аудио!") 67 | else: 68 | await message.edit("Отправка...") 69 | await reply.download_media("file.mp3") 70 | load = eyed3.load("file.mp3") 71 | load.tag.album = test 72 | load.tag.save() 73 | await reply.reply(file="file.mp3") 74 | -------------------------------------------------------------------------------- /cu.py: -------------------------------------------------------------------------------- 1 | from telethon import functions 2 | from .. import loader, utils 3 | from telethon.tl.functions.account import UpdateProfileRequest 4 | from telethon.tl.functions.users import GetFullUserRequest 5 | 6 | 7 | @loader.tds 8 | class CuMod(loader.Module): 9 | """Полное копирование юзера(ава, имя|фамилия, био)""" 10 | 11 | strings = {"name": "Cu"} 12 | 13 | @loader.owner 14 | async def cucmd(self, message): 15 | """.cu 16 | - Скрытый режим 17 | - Удалить ваши аватарки 18 | Аргументы после юзера не указывайте, не скушает 19 | Примеры: 20 | .cu s @user/reply 21 | .cu a @user/reply 22 | .cu s a @user/reply""" 23 | reply = await message.get_reply_message() 24 | user = None 25 | s = False 26 | a = False 27 | if utils.get_args_raw(message): 28 | args = utils.get_args_raw(message).split(" ") 29 | for i in args: 30 | if i.lower() == "s": 31 | s = True 32 | elif i.lower() in ["а", "a"]: 33 | a = True 34 | else: 35 | try: 36 | user = await message.client.get_entity(i) 37 | break 38 | except Exception: 39 | continue 40 | if user is None and reply is not None: 41 | user = reply.sender 42 | if user is None and reply is None: 43 | if not s: 44 | await message.edit("Кого?") 45 | return 46 | if s: 47 | await message.delete() 48 | 49 | if a: 50 | avs = await message.client.get_profile_photos("me") 51 | if len(avs) > 0: 52 | await message.client( 53 | functions.photos.DeletePhotosRequest( 54 | await message.client.get_profile_photos("me") 55 | ) 56 | ) 57 | full = await message.client(GetFullUserRequest(user.id)) 58 | if full.full_user.profile_photo: 59 | up = await message.client.upload_file( 60 | await message.client.download_profile_photo(user, bytes) 61 | ) 62 | await message.client(functions.photos.UploadProfilePhotoRequest(up)) 63 | await message.client( 64 | UpdateProfileRequest( 65 | user.first_name if user.first_name is not None else "", 66 | user.last_name if user.last_name is not None else "", 67 | full.full_user.about[:70] if full.full_user.about is not None else "", 68 | ) 69 | ) 70 | if not s: 71 | await message.edit("Аккаунт клонирован!") 72 | -------------------------------------------------------------------------------- /gg.gg.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Friendly Telegram (telegram userbot) 4 | # Copyright (C) 2018-2020 @DneZyeK | sub to @KeyZenD 5 | 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Affero General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU Affero General Public License for more details. 15 | 16 | # You should have received a copy of the GNU Affero General Public License 17 | # along with this program. If not, see . 18 | 19 | import logging 20 | from .. import loader, utils 21 | import telethon 22 | from requests import post 23 | 24 | logger = logging.getLogger(__name__) 25 | 26 | 27 | async def register(cb): 28 | cb(WhoIsMod()) 29 | 30 | 31 | @loader.tds 32 | class GGdotGGMod(loader.Module): 33 | """Сокращение ссылок через сервис gg.gg""" 34 | 35 | strings = { 36 | "name": "gg.gg", 37 | "some_rong": "Ты делаешь что-то не так!\nНапиши .help gg.gg для информации.", 38 | } 39 | 40 | async def client_ready(self, client, db): 41 | self.client = client 42 | 43 | async def ggcmd(self, message): 44 | """.gg <длинная ссылка или реплай на ссылку>""" 45 | m_text = utils.get_args_raw(message) 46 | if not m_text: 47 | reply = await message.get_reply_message() 48 | if not reply: 49 | await utils.answer(message, self.strings["some_rong"]) 50 | return 51 | long_url = reply.raw_text 52 | else: 53 | long_url = m_text 54 | 55 | if "http://" not in long_url and "https://" not in long_url: 56 | long_url = "http://" + long_url 57 | t_check = f"URL: {long_url}\nCheck..." 58 | await utils.answer(message, t_check) 59 | check = post( 60 | "http://gg.gg/check", 61 | data={ 62 | "custom_path": None, 63 | "use_norefs": "0", 64 | "long_url": long_url, 65 | "app": "site", 66 | "version": "0.1", 67 | }, 68 | ).text 69 | if check != "ok": 70 | await utils.answer(message, check) 71 | return 72 | await utils.answer(message, "Create...") 73 | short = post( 74 | "http://gg.gg/create", 75 | data={ 76 | "custom_path": None, 77 | "use_norefs": "0", 78 | "long_url": long_url, 79 | "app": "site", 80 | "version": "0.1", 81 | }, 82 | ).text 83 | await utils.answer(message, short) 84 | -------------------------------------------------------------------------------- /smiles.py: -------------------------------------------------------------------------------- 1 | from .. import loader 2 | from asyncio import sleep 3 | 4 | 5 | @loader.tds 6 | class HeartsMod(loader.Module): 7 | strings = {"name": "Magic of smiles"} 8 | 9 | @loader.owner 10 | async def heartscmd(self, message): 11 | for _ in range(10): 12 | for heart in ["❤", "🤎", "💛", "💚", "🤍", "💜"]: 13 | await message.edit(heart) 14 | await sleep(0.3) 15 | 16 | async def moonscmd(self, message): 17 | for _ in range(10): 18 | for moon in ["🌝", "🌚"]: 19 | await message.edit(moon) 20 | await sleep(0.3) 21 | 22 | async def moons2cmd(self, message): 23 | for _ in range(10): 24 | for moon2 in ["🌕", "🌖", "🌗", "🌘", "🌑", "🌒", "🌓", "🌔"]: 25 | await message.edit(moon2) 26 | await sleep(0.3) 27 | 28 | async def clockscmd(self, message): 29 | for _ in range(12): 30 | for clock in ["🕐", "🕑", "🕒", "🕓", "🕔", "🕕", "🕖", "🕗", "🕘", "🕙", "🕚", "🕛"]: 31 | await message.edit(clock) 32 | await sleep(0.3) 33 | 34 | async def policecmd(self, message): 35 | for _ in range(12): 36 | for police in [ 37 | "🔴🔴🔴🔴⬜️⬜️⬜️🔵🔵🔵🔵\n🔴🔴🔴🔴⬜️⬜️⬜️🔵🔵🔵🔵\n🔴🔴🔴🔴⬜️⬜️⬜️🔵🔵🔵🔵", 38 | "🔵🔵🔵🔵⬜️⬜️⬜️🔴🔴🔴🔴\n🔵🔵🔵🔵⬜️⬜️⬜️🔴🔴🔴🔴\n🔵🔵🔵🔵⬜️⬜️⬜️🔴🔴🔴🔴", 39 | ]: 40 | await message.edit(police) 41 | await sleep(0.3) 42 | 43 | async def dickcmd(self, message): 44 | await message.edit( 45 | "\u2060 💦\n❤️❤️❤️\n🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿🗿\n 🗿🗿🗿🗿🗿🗿\n 🗿🗿🗿 🗿🗿🗿\n 🗿🗿 🗿🗿" 46 | ) 47 | await sleep(1) 48 | await message.edit( 49 | "\u2060 💦\n 💦\n❤️❤️❤️\n🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿🗿\n 🗿🗿🗿🗿🗿🗿\n 🗿🗿🗿 🗿🗿🗿\n 🗿🗿 🗿🗿" 50 | ) 51 | await sleep(1) 52 | await message.edit( 53 | "\u2060 💦\n 💦\n 💦\n❤️❤️❤️\n🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n " 54 | "🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿🗿\n 🗿🗿🗿🗿🗿🗿\n 🗿🗿🗿 🗿🗿🗿\n 🗿🗿 🗿🗿" 55 | ) 56 | await sleep(1) 57 | await message.edit( 58 | "\u2060💦\n 💦\n 💦\n 💦\n❤️❤️❤️\n🗿🗿🗿\n 🗿🗿🗿\n " 59 | "🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿🗿\n 🗿🗿🗿🗿🗿🗿\n 🗿🗿🗿 🗿🗿🗿\n 🗿🗿 🗿🗿" 60 | ) 61 | await sleep(1) 62 | await message.edit( 63 | "\u2060💦💦\n💦\n💦\n 💦\n 💦\n 💦\n❤️❤️❤️\n🗿🗿🗿\n 🗿🗿🗿\n " 64 | "🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿\n 🗿🗿🗿🗿\n 🗿🗿🗿🗿🗿🗿\n 🗿🗿🗿 🗿🗿🗿\n 🗿🗿 🗿🗿" 65 | ) 66 | -------------------------------------------------------------------------------- /nhentai.py: -------------------------------------------------------------------------------- 1 | # requires: requests hentai 2 | 3 | import asyncio 4 | import logging 5 | 6 | from hentai import Hentai, Utils 7 | from requests.exceptions import HTTPError 8 | 9 | from .. import loader, utils 10 | 11 | logger = logging.getLogger(__name__) 12 | 13 | 14 | @loader.unrestricted 15 | @loader.ratelimit 16 | @loader.tds 17 | class NHentaiMod(loader.Module): 18 | """Hentai module 18+""" 19 | 20 | strings = { 21 | "name": "NHentai", 22 | } 23 | 24 | def StringBuilder(self, Hentai): 25 | id_nh = Hentai.id 26 | eng_name = Hentai.title() 27 | link = Hentai.url 28 | total_pages = Hentai.num_pages 29 | total_favorites = Hentai.num_favorites 30 | tags = "".join(f"{tag.name} " for tag in Hentai.tag) 31 | text = f"{eng_name} [{id_nh}]\n\n" 32 | text += f"{tags} \n" 33 | text += f"❤️ {total_favorites} | 📄 {total_pages}" 34 | return text 35 | 36 | def ListHentaiBuilder(self, Hentais): 37 | text = "" 38 | for i, Hentai in enumerate(Hentais, start=1): 39 | id_nh = Hentai.id 40 | eng_name = Hentai.title() 41 | link = Hentai.url 42 | total_pages = Hentai.num_pages 43 | total_favorites = Hentai.num_favorites 44 | 45 | text += f"{i}: {eng_name} [{id_nh}] / " 46 | text += f"❤️ {total_favorites} | 📄 {total_pages} \n" 47 | return text 48 | 49 | @loader.unrestricted 50 | @loader.ratelimit 51 | async def nhrandomcmd(self, message): 52 | """Random hentai manga""" 53 | await message.delete() 54 | hentai_info = Utils.get_random_hentai() 55 | text = self.StringBuilder(hentai_info) 56 | 57 | await message.client.send_file(message.chat_id, hentai_info.cover, caption=text) 58 | 59 | @loader.unrestricted 60 | @loader.ratelimit 61 | async def nhtagcmd(self, message): 62 | """Search hentai manga by tag""" 63 | args = utils.get_args(message) 64 | if args: 65 | hentai_info = Utils.search_by_query(args) 66 | text = self.ListHentaiBuilder(hentai_info) 67 | 68 | await utils.answer(message, text) 69 | else: 70 | await utils.answer(message, "Pls tags") 71 | await asyncio.sleep(5) 72 | await message.delete() 73 | 74 | @loader.unrestricted 75 | @loader.ratelimit 76 | async def nhidcmd(self, message): 77 | """Search hentai manga by id""" 78 | args = utils.get_args(message) 79 | if args[0].isdigit(): 80 | try: 81 | hentai_info = Hentai(args[0]) 82 | text = self.StringBuilder(hentai_info) 83 | await message.client.send_file( 84 | message.chat_id, hentai_info.cover, caption=text 85 | ) 86 | except HTTPError as e: 87 | await utils.answer(message, str(e)) 88 | await asyncio.sleep(5) 89 | await message.delete() 90 | else: 91 | await utils.answer(message, "Pls id") 92 | await asyncio.sleep(5) 93 | await message.delete() 94 | -------------------------------------------------------------------------------- /ctftools.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 t.me/innocoffee 3 | Licensed under the Apache License, Version 2.0 4 | 5 | Author is not responsible for any consequencies caused by using this 6 | software or any of its parts. If you have any questions or wishes, feel 7 | free to contact Dan by sending pm to @innocoffee_alt. 8 | """ 9 | 10 | 11 | # <3 title: CTF Toolkit 12 | # <3 pic: https://img.icons8.com/fluency/48/000000/user-credentials.png 13 | # <3 desc: Базовые инструменты, которые могут пригодиться на низкосортных CTF соревах 14 | 15 | 16 | from .. import loader, utils 17 | import os 18 | import time 19 | import io 20 | 21 | 22 | @loader.tds 23 | class CTFToolsMod(loader.Module): 24 | """CTF Toolkit.""" 25 | 26 | strings = { 27 | "name": "CTF Toolkit", 28 | "processing": "📤 Обработка...", 29 | "file_not_specified": "Мне какой файл читать, не подскажешь?... 🗿", 30 | "read_error": "🗿 Ошибка чтения файла", 31 | } 32 | 33 | async def filetypecmd(self, message): 34 | """Linux File command wrapper""" 35 | reply = await message.get_reply_message() 36 | message = await utils.answer(message, self.strings("processing", message)) 37 | if not reply and type(message.media) is None: 38 | await utils.answer(message, self.strings("file_not_specified", message)) 39 | return 40 | media = message.media if not reply else reply.media 41 | filename = f"/tmp/{str(round(time.time()))}.scan" 42 | 43 | file = await message.client.download_file(media) 44 | try: 45 | open(filename, "wb").write(file) 46 | 47 | res = str(os.popen(f"file {filename}").read()).replace(filename + ": ", "") 48 | os.system(f"rm -rf {filename}") 49 | 50 | await utils.answer(message, f"{res}") 51 | except Exception: 52 | await utils.answer(message, self.strings("read_error", message)) 53 | 54 | async def stringscmd(self, message): 55 | """Linux Strings | grep . command wrapper""" 56 | await utils.answer(message, self.strings("processing", message)) 57 | args = utils.get_args_raw(message) 58 | grep = "" if args == "" else f" | grep {args}" 59 | reply = await message.get_reply_message() 60 | if not reply and type(message.media) is None: 61 | await utils.answer(message, self.strings("file_not_specified", message)) 62 | return 63 | if not reply: 64 | media = message.media 65 | print(media) 66 | else: 67 | media = reply.media 68 | 69 | filename = f"/tmp/{str(round(time.time()))}" 70 | 71 | file = await message.client.download_file(media) 72 | try: 73 | open(filename, "wb").write(file) 74 | 75 | res = str(os.popen(f"strings {filename}{grep}").read()) 76 | os.system(f"rm -rf {filename}") 77 | try: 78 | await utils.answer(message, f"{res}") 79 | except Exception: 80 | txt = io.BytesIO(res.encode("utf-8")) 81 | txt.name = "strings_result.txt" 82 | await message.delete() 83 | await message.client.send_file(message.to_id, txt) 84 | except Exception: 85 | await utils.answer(message, self.strings("read_error", message)) 86 | -------------------------------------------------------------------------------- /voice_effects.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 t.me/megaass 3 | Licensed under the Apache License, Version 2.0 4 | 5 | Author is not responsible for any consequencies caused by using this 6 | software or any of its parts. If you have any questions or wishes, feel 7 | free to contact owner by sending pm to @megaass. 8 | 9 | Modded and code-refactoring by t.me/innocoffee 10 | """ 11 | 12 | from pydub import AudioSegment 13 | from .. import loader, utils 14 | from telethon import types 15 | import io 16 | import requests 17 | 18 | # requires: pydub 19 | 20 | overlays = {} 21 | 22 | 23 | async def create_overlay(message, reply): 24 | args = utils.get_args_raw(message).split() 25 | if args: 26 | overlay = args[0] 27 | vol = args[1] if len(args) > 1 else "" 28 | vol = 100 - min(int(vol), 99) if vol and vol.isdigit() else 100 29 | else: 30 | overlay = "pablo" 31 | 32 | if overlay not in overlays: 33 | overlay = overlays.keys()[0] 34 | 35 | voice = io.BytesIO() 36 | await reply.download_media(voice) 37 | voice.seek(0) 38 | voice = AudioSegment.from_file(voice) 39 | 40 | biogr = io.BytesIO(overlays[overlay]) 41 | biogr.seek(0) 42 | biogr = AudioSegment.from_file(biogr)[: len(voice)] - vol 43 | 44 | out = biogr.overlay(voice, position=0) 45 | output = io.BytesIO() 46 | output.name = f"{overlay}.ogg" 47 | out.export(output, format="ogg", bitrate="64k", codec="libopus") 48 | output.seek(0) 49 | 50 | return output, out 51 | 52 | 53 | class MinusMod(loader.Module): 54 | """Add voice overlays over messages""" 55 | 56 | strings = { 57 | "name": "VoiceEffects", 58 | "downloading": "Downloading", 59 | "no_audio": "You need to reply to audio", 60 | } 61 | 62 | async def client_ready(self, client, db): 63 | global overlays 64 | overlays = { 65 | "pablo": ( 66 | await utils.run_sync(requests.get, "https://x0.at/9z_9.mp3") 67 | ).content, 68 | "kids": ( 69 | await utils.run_sync(requests.get, "https://x0.at/4bfh.mp3") 70 | ).content, 71 | "camry": ( 72 | await utils.run_sync(requests.get, "https://x0.at/W8ui.mp3") 73 | ).content, 74 | "gta": ( 75 | await utils.run_sync(requests.get, "https://x0.at/KCkV.mp3") 76 | ).content, 77 | "amogus": ( 78 | await utils.run_sync(requests.get, "https://x0.at/wPms.mp3") 79 | ).content, 80 | "chill": ( 81 | await utils.run_sync(requests.get, "https://x0.at/JBs4.mp3") 82 | ).content, 83 | } 84 | 85 | async def handle_message(self, message): 86 | reply = await message.get_reply_message() 87 | if not reply or not reply.file or not reply.file.mime_type.startswith("audio"): 88 | return await utils.answer(message, self.strings("no_audio")) 89 | 90 | await utils.answer(message, self.strings("downloading")) 91 | output, out = await create_overlay(message, reply) 92 | await message.client.send_file( 93 | message.to_id, 94 | output, 95 | reply_to=reply.id, 96 | voice_note=True, 97 | duration=len(out) / 1000, 98 | ) 99 | await message.delete() 100 | 101 | async def sfcmd(self, message): 102 | """(in reply to voice) [volume]""" 103 | return await self.handle_message(message) 104 | -------------------------------------------------------------------------------- /translator.py: -------------------------------------------------------------------------------- 1 | # Friendly Telegram (telegram userbot) 2 | # Copyright (C) 2018-2019 The Authors 3 | 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU Affero General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU Affero General Public License for more details. 13 | 14 | # You should have received a copy of the GNU Affero General Public License 15 | # along with this program. If not, see . 16 | 17 | import logging 18 | import os 19 | 20 | try: 21 | import googletrans 22 | except ImportError: 23 | os.popen("python3 -m pip install googletrans==4.0.0-rc1").read() 24 | import googletrans 25 | 26 | from .. import loader, utils 27 | 28 | if googletrans.__version__ != "4.0.0-rc.1": 29 | raise KeyError( 30 | f'The googletrans version is {googletrans.__version__}, not "4.0.0-rc.1".' 31 | "It means the module cannot run properly. To fix this, reinstall googletrans==4.0.0-rc1." 32 | ) 33 | 34 | 35 | logger = logging.getLogger(__name__) 36 | 37 | 38 | def register(cb): 39 | cb(GTranslateMod()) 40 | 41 | 42 | @loader.tds 43 | class GTranslateMod(loader.Module): 44 | """Google Translator""" 45 | 46 | strings = { 47 | "name": "Google Translator", 48 | "translated": "[ {frlang} -> {to} ]\n{output}", 49 | "invalid_text": "Invalid text to translate", 50 | "split_error": "Python split() error, if there is -> in the text, it must split!", 51 | } 52 | 53 | def __init__(self): 54 | self.commands = {"gtranslate": self.gtranslatecmd} 55 | self.config = loader.ModuleConfig( 56 | "DEFAULT_LANG", "en", "Language to translate to by default" 57 | ) 58 | 59 | def config_complete(self): 60 | self.name = self.strings["name"] 61 | self.tr = googletrans.Translator() 62 | 63 | async def gtranslatecmd(self, message): 64 | """.gtranslate [from_lang->][->to_lang] """ 65 | args = utils.get_args(message) 66 | 67 | if len(args) == 0 or "->" not in args[0]: 68 | text = " ".join(args) 69 | args = ["", self.config["DEFAULT_LANG"]] 70 | else: 71 | text = " ".join(args[1:]) 72 | args = args[0].split("->") 73 | 74 | if len(text) == 0 and message.is_reply: 75 | text = (await message.get_reply_message()).message 76 | if len(text) == 0: 77 | await message.edit(self.strings["invalid_text"]) 78 | return 79 | if args[0] == "": 80 | args[0] = (await utils.run_sync(self.tr.detect, text)).lang 81 | if len(args) == 3: 82 | del args[1] 83 | if len(args) == 1: 84 | logging.error(self.strings["split_error"]) 85 | raise RuntimeError() 86 | if args[1] == "": 87 | args[1] = self.config["DEFAULT_LANG"] 88 | args[0] = args[0].lower() 89 | logger.debug(args) 90 | translated = ( 91 | await utils.run_sync(self.tr.translate, text, dest=args[1], src=args[0]) 92 | ).text 93 | ret = self.strings["translated"] 94 | ret = ret.format( 95 | text=utils.escape_html(text), 96 | frlang=utils.escape_html(args[0]), 97 | to=utils.escape_html(args[1]), 98 | output=utils.escape_html(translated), 99 | ) 100 | await utils.answer(message, ret) 101 | -------------------------------------------------------------------------------- /circles.py: -------------------------------------------------------------------------------- 1 | from .. import loader, utils # pylint: disable=relative-beyond-top-level 2 | from PIL import Image, ImageDraw, ImageOps, ImageFilter 3 | import io 4 | from telethon.tl.types import DocumentAttributeFilename 5 | import logging 6 | from moviepy.editor import VideoFileClip 7 | import os 8 | 9 | 10 | logger = logging.getLogger(__name__) 11 | 12 | 13 | @loader.tds 14 | class CirclesMod(loader.Module): 15 | """округляет всё""" 16 | 17 | strings = {"name": "Circles"} 18 | 19 | def __init__(self): 20 | self.name = self.strings["name"] 21 | 22 | async def client_ready(self, client, db): 23 | self.client = client 24 | 25 | @loader.sudo 26 | async def roundcmd(self, message): 27 | """.round """ 28 | reply = None 29 | if message.is_reply: 30 | reply = await message.get_reply_message() 31 | data = await check_media(reply) 32 | if isinstance(data, bool): 33 | await utils.answer( 34 | message, "Reply to image/sticker or video/gif!" 35 | ) 36 | return 37 | else: 38 | await utils.answer(message, "Reply to image/sticker or video/gif!") 39 | return 40 | data, type = data 41 | if type == "img": 42 | await message.edit("Processing image📷") 43 | img = io.BytesIO() 44 | bytes = await message.client.download_file(data, img) 45 | im = Image.open(img) 46 | w, h = im.size 47 | img = Image.new("RGBA", (w, h), (0, 0, 0, 0)) 48 | img.paste(im, (0, 0)) 49 | m = min(w, h) 50 | img = img.crop(((w - m) // 2, (h - m) // 2, (w + m) // 2, (h + m) // 2)) 51 | w, h = img.size 52 | mask = Image.new("L", (w, h), 0) 53 | draw = ImageDraw.Draw(mask) 54 | draw.ellipse((10, 10, w - 10, h - 10), fill=255) 55 | mask = mask.filter(ImageFilter.GaussianBlur(2)) 56 | img = ImageOps.fit(img, (w, h)) 57 | img.putalpha(mask) 58 | im = io.BytesIO() 59 | im.name = "img.webp" 60 | img.save(im) 61 | im.seek(0) 62 | await message.client.send_file(message.to_id, im, reply_to=reply) 63 | else: 64 | await message.edit("Processing video🎥") 65 | await message.client.download_file(data, "video.mp4") 66 | video = VideoFileClip("video.mp4") 67 | video.reader.close() 68 | w, h = video.size 69 | m = min(w, h) 70 | box = [(w - m) // 2, (h - m) // 2, (w + m) // 2, (h + m) // 2] 71 | video = video.crop(*box) 72 | await message.edit("Saving video📼") 73 | video.write_videofile("result.mp4") 74 | await message.client.send_file( 75 | message.to_id, "result.mp4", video_note=True, reply_to=reply 76 | ) 77 | os.remove("video.mp4") 78 | os.remove("result.mp4") 79 | await message.delete() 80 | 81 | 82 | async def check_media(reply): 83 | type = "img" 84 | if reply and reply.media and reply.photo: 85 | data = reply.photo 86 | elif reply and reply.media and reply.document: 87 | if ( 88 | DocumentAttributeFilename(file_name="AnimatedSticker.tgs") 89 | in reply.media.document.attributes 90 | ): 91 | return False 92 | if reply.gif or reply.video: 93 | type = "vid" 94 | if reply.audio or reply.voice: 95 | return False 96 | data = reply.media.document 97 | else: 98 | return False 99 | if not data or data is None: 100 | return False 101 | else: 102 | return (data, type) 103 | -------------------------------------------------------------------------------- /megamozg.py: -------------------------------------------------------------------------------- 1 | # @KeyZenD & @D4n13l3k00 2 | 3 | import random 4 | 5 | from telethon import types 6 | 7 | from .. import loader, utils 8 | 9 | 10 | @loader.tds 11 | class MegaMozgMod(loader.Module): 12 | strings = { 13 | "name": "MegaMozg", 14 | "pref": "[MegaMozg] ", 15 | "need_arg": "{}Нужен аргумент", 16 | "status": "{}{}", 17 | "on": "{}Включён", 18 | "off": "{}Выключен", 19 | } 20 | _db_name = "MegaMozg" 21 | 22 | async def client_ready(self, _, db): 23 | self.db = db 24 | 25 | @staticmethod 26 | def str2bool(v): 27 | return v.lower() in ( 28 | "yes", 29 | "y", 30 | "ye", 31 | "yea", 32 | "true", 33 | "t", 34 | "1", 35 | "on", 36 | "enable", 37 | "start", 38 | "run", 39 | "go", 40 | "да", 41 | ) 42 | 43 | async def mozgcmd(self, m: types.Message): 44 | ".mozg - Переключить режим дурачка в чате" 45 | args = utils.get_args_raw(m) 46 | if not m.chat: 47 | return 48 | chat = m.chat.id 49 | if self.str2bool(args): 50 | chats: list = self.db.get(self._db_name, "chats", []) 51 | chats.append(chat) 52 | chats = list(set(chats)) 53 | self.db.set(self._db_name, "chats", chats) 54 | return await utils.answer( 55 | m, self.strings("on").format(self.strings("pref")) 56 | ) 57 | chats: list = self.db.get(self._db_name, "chats", []) 58 | try: 59 | chats.remove(chat) 60 | except: 61 | pass 62 | chats = list(set(chats)) 63 | self.db.set(self._db_name, "chats", chats) 64 | return await utils.answer(m, self.strings("off").format(self.strings("pref"))) 65 | 66 | async def mozgchancecmd(self, m: types.Message): 67 | ".mozgchance - Устанвоить шанс 1 к N.\n0 - всегда отвечать" 68 | args: str = utils.get_args_raw(m) 69 | if args.isdigit(): 70 | self.db.set(self._db_name, "chance", int(args)) 71 | return await utils.answer( 72 | m, self.strings("status").format(self.strings("pref"), args) 73 | ) 74 | 75 | return await utils.answer( 76 | m, self.strings("need_arg").format(self.strings("pref")) 77 | ) 78 | 79 | async def watcher(self, m: types.Message): 80 | if not isinstance(m, types.Message): 81 | return 82 | if m.sender_id == (await m.client.get_me()).id or not m.chat: 83 | return 84 | if m.chat.id not in self.db.get(self._db_name, "chats", []): 85 | return 86 | ch = self.db.get(self._db_name, "chance", 0) 87 | if ch != 0 and random.randint(0, ch) != 0: 88 | return 89 | text = m.raw_text 90 | words = { 91 | random.choice(list(filter(lambda x: len(x) >= 3, text.split()))) 92 | for _ in ".." 93 | } 94 | msgs = [] 95 | for word in words: 96 | [ 97 | msgs.append(x) 98 | async for x in m.client.iter_messages(m.chat.id, search=word) 99 | if x.replies and x.replies.max_id 100 | ] 101 | replier = random.choice(msgs) 102 | sid = replier.id 103 | eid = replier.replies.max_id 104 | msgs = [ 105 | x 106 | async for x in m.client.iter_messages( 107 | m.chat.id, ids=list(range(sid + 1, eid + 1)) 108 | ) 109 | if x and x.reply_to and x.reply_to.reply_to_msg_id == sid 110 | ] 111 | msg = random.choice(msgs) 112 | await m.reply(msg) 113 | -------------------------------------------------------------------------------- /DNA.py: -------------------------------------------------------------------------------- 1 | # requires: pillow 2 | # requires: wand 3 | from .. import loader, utils 4 | import io 5 | from telethon.tl.types import DocumentAttributeFilename 6 | import logging 7 | from wand.image import Image 8 | from PIL import Image as IM 9 | 10 | # https://t.me/KeyZenD 11 | # https://t.me/govnocodules 12 | # https://t.me/DneZyeK 13 | logger = logging.getLogger(__name__) 14 | 15 | 16 | @loader.tds 17 | class DistortNoApiMod(loader.Module): 18 | """distorting images""" 19 | 20 | strings = {"name": "DistortNoApi"} 21 | 22 | async def client_ready(self, client, db): 23 | self.client = client 24 | 25 | @loader.sudo 26 | async def distortcmd(self, message): 27 | """.distort 28 | .distort im 29 | .distort 50 30 | .distort 50 im 31 | .distort im 50 32 | im => кидает стикеры как фото 33 | 50 => (от 0 до дохуя) процент сжатия""" 34 | if message.is_reply: 35 | reply_message = await message.get_reply_message() 36 | data, mime = await check_media(reply_message) 37 | if isinstance(data, bool): 38 | await utils.answer(message, "Reply to image or stick!") 39 | return 40 | else: 41 | await utils.answer(message, "Reply to image or stick!") 42 | return 43 | rescale_rate = 70 44 | a = utils.get_args(message) 45 | force_file = False 46 | if a: 47 | if "im" in a: 48 | force_file = True 49 | a.remove("im") 50 | if len(a) > 0: 51 | if a[0].isdigit(): 52 | rescale_rate = int(a[0]) 53 | if rescale_rate <= 0: 54 | rescale_rate = 70 55 | 56 | await message.edit("D i s t o r t i n g . . .") 57 | file = await message.client.download_media(data, bytes) 58 | file, img = io.BytesIO(file), io.BytesIO() 59 | img.name = "img.png" 60 | IM.open(file).save(img, "PNG") 61 | media = await distort(io.BytesIO(img.getvalue()), rescale_rate) 62 | out, im = io.BytesIO(), IM.open(media) 63 | if force_file: 64 | mime = "png" 65 | out.name = f"out.{mime}" 66 | im.save(out, mime.upper()) 67 | out.seek(0) 68 | await message.edit("S e n d i n g . . .") 69 | await message.client.send_file(message.to_id, out, reply_to=reply_message.id) 70 | 71 | await message.delete() 72 | 73 | 74 | async def distort(file, rescale_rate): 75 | img = Image(file=file) 76 | x, y = img.size[0], img.size[1] 77 | popx = int(rescale_rate * (x // 100)) 78 | popy = int(rescale_rate * (y // 100)) 79 | img.liquid_rescale(popx, popy, delta_x=1, rigidity=0) 80 | img.resize(x, y) 81 | out = io.BytesIO() 82 | out.name = "output.png" 83 | img.save(file=out) 84 | return io.BytesIO(out.getvalue()) 85 | 86 | 87 | async def check_media(reply_message): 88 | mime = None 89 | if reply_message and reply_message.media and reply_message.photo: 90 | data = reply_message.photo 91 | mime = "image/jpeg" 92 | elif reply_message and reply_message.media and reply_message.document: 93 | if ( 94 | DocumentAttributeFilename(file_name="AnimatedSticker.tgs") 95 | in reply_message.media.document.attributes 96 | ): 97 | return False, mime 98 | if ( 99 | reply_message.gif 100 | or reply_message.video 101 | or reply_message.audio 102 | or reply_message.voice 103 | ): 104 | return False, mime 105 | data = reply_message.media.document 106 | mime = reply_message.media.document.mime_type 107 | if "image/" not in mime: 108 | return False, mime 109 | else: 110 | return False, mime 111 | if not data or data is None: 112 | return False, mime 113 | mime = mime.split("/")[1] 114 | return data, mime 115 | -------------------------------------------------------------------------------- /purge.py: -------------------------------------------------------------------------------- 1 | # Friendly Telegram (telegram userbot) 2 | # Copyright (C) 2018-2019 The Authors 3 | 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU Affero General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU Affero General Public License for more details. 13 | 14 | # You should have received a copy of the GNU Affero General Public License 15 | # along with this program. If not, see . 16 | 17 | from .. import loader, utils 18 | import logging 19 | import telethon 20 | 21 | logger = logging.getLogger(__name__) 22 | 23 | 24 | @loader.tds 25 | class PurgeMod(loader.Module): 26 | """Deletes your messages""" 27 | 28 | strings = { 29 | "name": "Purge", 30 | "from_where": "Which messages should be purged?", 31 | "not_supergroup_bot": "Purges can only take place in supergroups", 32 | "delete_what": "What message should be deleted?", 33 | } 34 | 35 | @loader.group_admin_delete_messages 36 | @loader.ratelimit 37 | async def purgecmd(self, message): 38 | """Purge from the replied message""" 39 | if not message.is_reply: 40 | await utils.answer(message, self.strings("from_where", message)) 41 | return 42 | 43 | from_users = set() 44 | args = utils.get_args(message) 45 | for arg in args: 46 | try: 47 | entity = await message.client.get_entity(arg) 48 | if isinstance(entity, telethon.tl.types.User): 49 | from_users.add(entity.id) 50 | except ValueError: 51 | pass 52 | 53 | msgs = [] 54 | from_ids = set() 55 | if await message.client.is_bot(): 56 | if not message.is_channel: 57 | await utils.answer(message, self.strings("not_supergroup_bot", message)) 58 | return 59 | for msg in range(message.reply_to_msg_id, message.id + 1): 60 | msgs.append(msg) 61 | if len(msgs) >= 99: 62 | logger.debug(msgs) 63 | await message.client.delete_messages(message.to_id, msgs) 64 | msgs.clear() 65 | else: 66 | async for msg in message.client.iter_messages( 67 | entity=message.to_id, min_id=message.reply_to_msg_id - 1, reverse=True 68 | ): 69 | if from_users and msg.sender_id not in from_users: 70 | continue 71 | msgs.append(msg.id) 72 | from_ids.add(msg.sender_id) 73 | if len(msgs) >= 99: 74 | logger.debug(msgs) 75 | await message.client.delete_messages(message.to_id, msgs) 76 | msgs.clear() 77 | if msgs: 78 | logger.debug(msgs) 79 | await message.client.delete_messages(message.to_id, msgs) 80 | await self.allmodules.log("purge", group=message.to_id, affected_uids=from_ids) 81 | 82 | @loader.group_admin_delete_messages 83 | @loader.ratelimit 84 | async def delcmd(self, message): 85 | """Delete the replied message""" 86 | msgs = [message.id] 87 | if not message.is_reply: 88 | if await message.client.is_bot(): 89 | await utils.answer(message, self.strings("delete_what", message)) 90 | return 91 | msg = await message.client.iter_messages( 92 | message.to_id, 1, max_id=message.id 93 | ).__anext__() 94 | else: 95 | msg = await message.get_reply_message() 96 | msgs.append(msg.id) 97 | logger.debug(msgs) 98 | await message.client.delete_messages(message.to_id, msgs) 99 | await self.allmodules.log( 100 | "delete", group=message.to_id, affected_uids=[msg.sender_id] 101 | ) 102 | -------------------------------------------------------------------------------- /text-to-speech.py: -------------------------------------------------------------------------------- 1 | # requires: pydub requests gtts hachoir 2 | import io 3 | import os 4 | import requests 5 | from .. import loader, utils 6 | from pydub import AudioSegment 7 | from gtts import gTTS 8 | from subprocess import DEVNULL, STDOUT, check_call 9 | 10 | 11 | def register(cb): 12 | cb(DttsMod()) 13 | 14 | 15 | class DttsMod(loader.Module): 16 | """Text to speech module""" 17 | 18 | strings = { 19 | "name": "DTTS", 20 | "no_text": "I can't say nothing", 21 | "tts_lang_cfg": "Set your language code for the TTS here.", 22 | } 23 | 24 | def __init__(self): 25 | self.config = loader.ModuleConfig( 26 | "TTS_LANG", "en", lambda m: self.strings("tts_lang_cfg", m) 27 | ) 28 | self.is_ffmpeg = ( 29 | check_call(["ffmpeg", "-version"], stdout=DEVNULL, stderr=STDOUT) == 0 30 | ) 31 | 32 | async def say(self, message, speaker, text, file=".dtts.mp3"): 33 | reply = await message.get_reply_message() 34 | if not text: 35 | if not reply: 36 | return await utils.answer(message, self.strings["no_text"]) 37 | text = reply.raw_text # use text from reply 38 | if not text: 39 | return await utils.answer(message, self.strings["no_text"]) 40 | if message.out: 41 | await message.delete() # Delete message only one is user's 42 | data = {"text": text} 43 | if speaker: 44 | data["speaker"] = speaker 45 | # creating file in memory 46 | f = io.BytesIO( 47 | requests.get("https://station.aimylogic.com/generate", data=data).content 48 | ) 49 | f.name = file 50 | 51 | if self.is_ffmpeg: 52 | f, duration = to_voice(f) 53 | else: 54 | duration = None 55 | 56 | await message.client.send_file( 57 | message.chat_id, f, voice_note=True, reply_to=reply, duration=duration 58 | ) 59 | 60 | @loader.unrestricted 61 | @loader.ratelimit 62 | async def levitancmd(self, message): 63 | """Convert text to speech with levitan voice""" 64 | await self.say(message, "levitan", utils.get_args_raw(message)) 65 | 66 | @loader.unrestricted 67 | @loader.ratelimit 68 | async def oksanacmd(self, message): 69 | """Convert text to speech with oksana voice""" 70 | await self.say(message, "oksana", utils.get_args_raw(message)) 71 | 72 | @loader.unrestricted 73 | @loader.ratelimit 74 | async def yandexcmd(self, message): 75 | """Convert text to speech with yandex voice""" 76 | await self.say(message, None, utils.get_args_raw(message)) 77 | 78 | @loader.unrestricted 79 | @loader.ratelimit 80 | async def ttscmd(self, message): 81 | """Convert text to speech with Google APIs""" 82 | reply = await message.get_reply_message() 83 | text = utils.get_args_raw(message.message) 84 | 85 | if not text: 86 | if message.is_reply: 87 | text = (await message.get_reply_message()).message 88 | else: 89 | return await utils.answer(message, self.strings("no_text", message)) 90 | 91 | if message.out: 92 | await message.delete() 93 | 94 | tts = await utils.run_sync(gTTS, text, lang=self.config["TTS_LANG"]) 95 | voice = io.BytesIO() 96 | await utils.run_sync(tts.write_to_fp, voice) 97 | voice.seek(0) 98 | voice.name = "voice.mp3" 99 | 100 | if self.is_ffmpeg: 101 | voice, duration = to_voice(voice) 102 | else: 103 | duration = None 104 | 105 | await message.client.send_file( 106 | message.chat_id, voice, voice_note=True, reply_to=reply, duration=duration 107 | ) 108 | 109 | 110 | def to_voice(item): 111 | """Returns audio in opus format and it's duration""" 112 | item.seek(0) 113 | item = AudioSegment.from_file(item) 114 | m = io.BytesIO() 115 | m.name = "voice.ogg" 116 | item.split_to_mono() 117 | dur = len(item) / 1000 118 | item.export(m, format="ogg", bitrate="64k", codec="libopus") 119 | m.seek(0) 120 | return m, dur 121 | 122 | 123 | # By @vreply @pernel_kanic @nim1love @db0mb3r and add @tshipenchko some geyporn 124 | -------------------------------------------------------------------------------- /farmiris.py: -------------------------------------------------------------------------------- 1 | # for more info: https://murix.ru/files/ftg 2 | # by xadjilut, 2021 3 | 4 | import random 5 | from .. import loader, utils 6 | from datetime import timedelta 7 | from telethon import functions 8 | from telethon.tl.types import Message 9 | 10 | 11 | @loader.tds 12 | class FarmIrisMod(loader.Module): 13 | """Для автоматического фарминга коинов в ирисботе""" 14 | 15 | strings = { 16 | "name": "farmiris", 17 | "farmon": "✅Отложенка создана, автофарминг запущен, всё начнётся через 20 секунд...", 18 | "farmon_already": "Уже запущено", 19 | "farmoff": "❌Автофарминг остановлен.\n☢️Надюпано: %coins% i¢", 20 | "farm": "☢️Надюпано: %coins% i¢", 21 | } 22 | 23 | def __init__(self): 24 | self.name = self.strings["name"] 25 | 26 | async def client_ready(self, client, db): 27 | self.client = client 28 | self.db = db 29 | self.myid = (await client.get_me()).id 30 | self.iris = 707693258 31 | 32 | async def farmoncmd(self, message): 33 | """Запустить автофарминг""" 34 | status = self.db.get(self.name, "status", False) 35 | if status: 36 | return await message.edit(self.strings["farmon_already"]) 37 | self.db.set(self.name, "status", True) 38 | await self.client.send_message( 39 | self.iris, "Фарма", schedule=timedelta(seconds=20) 40 | ) 41 | await message.edit(self.strings["farmon"]) 42 | 43 | async def farmoffcmd(self, message): 44 | """Остановить автофарминг""" 45 | self.db.set(self.name, "status", False) 46 | coins = self.db.get(self.name, "coins", 0) 47 | if coins: 48 | self.db.set(self.name, "coins", 0) 49 | await message.edit(self.strings["farmoff"].replace("%coins%", str(coins))) 50 | 51 | async def farmcmd(self, message): 52 | """Вывод кол-ва коинов, добытых этим модулем""" 53 | coins = self.db.get(self.name, "coins", 0) 54 | await message.edit(self.strings["farm"].replace("%coins%", str(coins))) 55 | 56 | async def watcher(self, event): 57 | if not isinstance(event, Message): 58 | return 59 | chat = utils.get_chat_id(event) 60 | if chat != self.iris: 61 | return 62 | status = self.db.get(self.name, "status", False) 63 | if not status: 64 | return 65 | if event.raw_text == "Фарма": 66 | return await self.client.send_message( 67 | self.iris, "Фарма", schedule=timedelta(minutes=random.randint(1, 20)) 68 | ) 69 | if event.sender_id != self.iris: 70 | return 71 | if "НЕЗАЧЁТ!" in event.raw_text: 72 | args = [int(x) for x in event.raw_text.split() if x.isnumeric()] 73 | randelta = random.randint(20, 60) 74 | if len(args) == 4: 75 | delta = timedelta( 76 | hours=args[1], minutes=args[2], seconds=args[3] + randelta 77 | ) 78 | elif len(args) == 3: 79 | delta = timedelta(minutes=args[1], seconds=args[2] + randelta) 80 | elif len(args) == 2: 81 | delta = timedelta(seconds=args[1] + randelta) 82 | else: 83 | return 84 | sch = ( 85 | await self.client( 86 | functions.messages.GetScheduledHistoryRequest(self.iris, 1488) 87 | ) 88 | ).messages 89 | await self.client( 90 | functions.messages.DeleteScheduledMessagesRequest( 91 | self.iris, id=[x.id for x in sch] 92 | ) 93 | ) 94 | return await self.client.send_message(self.iris, "Фарма", schedule=delta) 95 | if "ЗАЧЁТ" in event.raw_text or "УДАЧА" in event.raw_text: 96 | args = event.raw_text.split() 97 | for x in args: 98 | if x[0] == "+": 99 | return self.db.set( 100 | self.name, 101 | "coins", 102 | self.db.get(self.name, "coins", 0) + int(x[1:]), 103 | ) 104 | -------------------------------------------------------------------------------- /nsfw.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 t.me/innocoffee 3 | Licensed under the Apache License, Version 2.0 4 | 5 | Author is not responsible for any consequencies caused by using this 6 | software or any of its parts. If you have any questions or wishes, feel 7 | free to contact Dan by sending pm to @innocoffee_alt. 8 | """ 9 | 10 | # meta pic: https://img.icons8.com/fluency/48/000000/keep-away-from-children.png 11 | 12 | from .. import loader, utils 13 | import requests 14 | import os 15 | 16 | # requires: requests 17 | 18 | 19 | @loader.tds 20 | class NSFWMod(loader.Module): 21 | """Кидает рандомную картинку NSFW содержания с scroller""" 22 | strings = { 23 | "name": "NSFW", 24 | "sreddit404": "🦊 Subreddit not found", 25 | "default_subreddit": "🦊 Set new default subreddit: {}", 26 | "loading": "🦊 Loading...", 27 | } 28 | 29 | async def client_ready(self, client, db): 30 | self.db = db 31 | self.client = client 32 | 33 | async def nsfwcmd(self, message): 34 | """.nsfw [-n ] - Send random NSFW picture""" 35 | args = utils.get_args_raw(message) 36 | message = await utils.answer(message, self.strings("loading", message)) 37 | try: 38 | message = message[0] 39 | except: 40 | pass 41 | 42 | if "-n" in args: 43 | try: 44 | quantity = int(args[args.find("-n") + 2 :]) 45 | except: 46 | quantity = 1 47 | 48 | args = args[: args.find("-n")] 49 | else: 50 | quantity = 1 51 | 52 | args = args.strip() 53 | 54 | if not args: 55 | args = self.db.get("NSFW", "default_subreddit", "nsfw") 56 | 57 | subreddit = f"/r/{args}" 58 | 59 | logger.info(f"[NSFW]: Fetching {quantity} photos from {subreddit}") 60 | 61 | ans = requests.get(f"https://api.scrolller.com{subreddit}") 62 | if ans.status_code != 200: 63 | await utils.answer(message, self.strings("sreddit404", message)) 64 | return 65 | 66 | ans = requests.get( 67 | "https://api.scrolller.com/api/v2/graphql", 68 | json={ 69 | "query": " query SubredditQuery( $url: String! $filter: SubredditPostFilter $iterator: String ) { getSubreddit(url: $url) { children( limit: " 70 | + str(quantity) 71 | + " iterator: $iterator filter: $filter ) { iterator items { __typename url title subredditTitle subredditUrl redditPath isNsfw albumUrl isFavorite mediaSources { url width height isOptimized } } } } } ", 72 | "variables": {"filter": None, "url": subreddit}, 73 | "authorization": None, 74 | }, 75 | ).json() 76 | posts = ans["data"]["getSubreddit"]["children"]["items"] 77 | res = [] 78 | for i in range(min(quantity, len(posts))): 79 | url = posts[i]["mediaSources"][0]["url"] 80 | fname = url.split("/")[-1] 81 | open(f"/tmp/{fname}", "wb").write(requests.get(url).content) 82 | res.append(f"/tmp/{fname}") 83 | 84 | if quantity == 1: 85 | title = posts[0]["title"] 86 | else: 87 | title = f"{quantity} photos from subreddit {subreddit}" 88 | await self.client.send_file( 89 | utils.get_chat_id(message), 90 | file=res, 91 | caption=f"{utils.escape_html(title)}", 92 | parse_mode="HTML", 93 | ) 94 | 95 | for path in res: 96 | try: 97 | os.remove(path) 98 | except Exception: 99 | pass 100 | await message.delete() 101 | 102 | async def nsfwcatcmd(self, message): 103 | """.nsfwcat - Set new default subreddit""" 104 | args = utils.get_args_raw(message) 105 | if not args: 106 | args = "nsfw" 107 | 108 | ans = requests.get(f"https://api.scrolller.com/r/{args}") 109 | if ans.status_code != 200: 110 | await utils.answer(message, self.strings("sreddit404", message)) 111 | return 112 | 113 | self.db.set("NSFW", "default_subreddit", args) 114 | await utils.answer( 115 | message, self.strings("default_subreddit", message).format(args) 116 | ) 117 | -------------------------------------------------------------------------------- /kicklast.py: -------------------------------------------------------------------------------- 1 | # @KeyZenD & @D4n13l3k00 2 | # requires: bs4 aiogram 3 | 4 | from random import choice 5 | from string import ascii_lowercase 6 | 7 | from aiogram import Bot 8 | from bs4 import BeautifulSoup as bs4 9 | from telethon import events, functions, types 10 | from telethon.tl.functions.channels import InviteToChannelRequest 11 | from telethon.tl.types import Channel 12 | 13 | from .. import loader, utils 14 | 15 | 16 | class KickLastMod(loader.Module): 17 | """Удаляет из чата последних Х зашедших""" 18 | 19 | strings = { 20 | "name": "KickLast", 21 | "pref": "[KickLast] ", 22 | "cdne": "{}Такого чата не существует", 23 | "cfju": "{}Не могу обнаружить зашедших...", 24 | "success": "{}Операция завершена! Кикнуто {} юзеров", 25 | "found": "{}Найдено {} зашедших юзеров! Кикаю...", 26 | "howmany": "{}Сколько нужно кикнуть?\n0 если всех зашедших за 48 часов", 27 | "createerr": "{}Создание бота недоступно.\nПовтори попытку через {}", 28 | } 29 | 30 | async def botkicklastcmd(self, message): 31 | """.botkicklst <количество> <юзернейм, если канал> - Кикает при помощи тг бота""" 32 | await kick(self, message, True) 33 | 34 | async def kicklastcmd(self, message): 35 | """.kicklst <количество> <юзернейм, если канал> - Кикает юзерботом""" 36 | await kick(self, message, False) 37 | 38 | 39 | async def kick(self, message, bot=False): 40 | client = message.client 41 | args = utils.get_args(message) 42 | if not args: 43 | return await utils.answer( 44 | message, self.strings("howmany").format(self.strings("pref")) 45 | ) 46 | limit = int(args[0]) 47 | limit = limit or 99999 48 | group = args[-1] if len(args) > 1 else message.chat.id 49 | try: 50 | group = await client.get_entity(group) 51 | except: 52 | await utils.answer(message, self.strings("cdne").format(self.strings("pref"))) 53 | if not isinstance(group, Channel): 54 | return await utils.answer( 55 | message, self.strings("cdne").format(self.strings("pref")) 56 | ) 57 | if bot: 58 | botfather = 93372553 59 | bantoolbot = "".join(choice(list(ascii_lowercase)) for _ in range(29)) + "bot" 60 | async with client.conversation(botfather) as conv: 61 | await (await client.send_message(botfather, "/newbot")).delete() 62 | newbot = await conv.wait_event( 63 | events.NewMessage(incoming=True, from_users=botfather) 64 | ) 65 | await newbot.delete() 66 | if "Sorry" in newbot.text: 67 | return await utils.answer( 68 | message, 69 | self.strings("howmany").format( 70 | self.strings("pref"), newbot.text[45:] 71 | ), 72 | ) 73 | await (await client.send_message(botfather, "BanTool")).delete() 74 | await ( 75 | await conv.wait_event( 76 | events.NewMessage(incoming=True, from_users=botfather) 77 | ) 78 | ).delete() 79 | await (await client.send_message(botfather, bantoolbot)).delete() 80 | html = await conv.wait_event( 81 | events.NewMessage(incoming=True, from_users=botfather) 82 | ) 83 | await html.delete() 84 | soup = bs4(html.text, "html.parser") 85 | token = soup.findAll("code")[0].text 86 | await client(InviteToChannelRequest(group, [bantoolbot])) 87 | await client( 88 | functions.channels.EditAdminRequest( 89 | channel=group, 90 | user_id=bantoolbot, 91 | admin_rights=types.ChatAdminRights(ban_users=True), 92 | rank="BanToolBot", 93 | ) 94 | ) 95 | banlist = [ 96 | x.user_id async for x in client.iter_admin_log(group, join=True, limit=limit) 97 | ] 98 | 99 | message = await utils.answer( 100 | message, self.strings("found").format(self.strings("pref"), str(len(banlist))) 101 | ) 102 | if not banlist: 103 | return await utils.answer( 104 | message, self.strings("cfju").format(self.strings("pref")) 105 | ) 106 | for banid in banlist: 107 | if bot: 108 | await Bot(token).kick_chat_member(f"-100{group}", banid) 109 | else: 110 | await client.kick_participant(group, banid) 111 | if bot: 112 | await client.kick_participant(group, bantoolbot) 113 | async with client.conversation(botfather) as conv: 114 | await client.send_message(botfather, "/deletebot") 115 | await conv.wait_event( 116 | events.NewMessage(incoming=True, from_users=botfather) 117 | ) 118 | await client.send_message(botfather, "@" + bantoolbot) 119 | await conv.wait_event( 120 | events.NewMessage(incoming=True, from_users=botfather) 121 | ) 122 | await client.send_message(botfather, "Yes, I am totally sure.") 123 | return await utils.answer( 124 | message, self.strings("success").format(self.strings("pref"), str(len(banlist))) 125 | ) 126 | -------------------------------------------------------------------------------- /sysinfo.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | import os 4 | import platform 5 | import shutil 6 | import sys 7 | 8 | import telethon 9 | 10 | from .. import loader, utils 11 | 12 | logger = logging.getLogger(__name__) 13 | 14 | 15 | @loader.tds 16 | class InfoMod(loader.Module): 17 | """Provides system information about the computer hosting this bot""" 18 | 19 | strings = { 20 | "name": "System Info", 21 | "info_title": "System Info", 22 | "kernel": "Kernel: {}", 23 | "arch": "Arch: {}", 24 | "os": "OS: {}", 25 | "heroku": "FTG Installed on Heroku", 26 | "distro": "Linux Distribution: {}", 27 | "android_sdk": "Android SDK: {}", 28 | "android_ver": "Android Version: {}", 29 | "android_patch": "Android Security Patch: {}", 30 | "unknown_distro": "Could not determine Linux distribution.", 31 | "python_version": "Python version: {}", 32 | "telethon_version": "Telethon version: {}", 33 | "git_version": "Git version: {}", 34 | "ftg_type": "FTG Type: {}", 35 | } 36 | 37 | async def infocmd(self, message): 38 | """Shows system information""" 39 | ftg_type = "PC/Server" 40 | reply = self.strings("info_title", message) 41 | reply += "\n" + self.strings("kernel", message).format( 42 | utils.escape_html(platform.release()) 43 | ) 44 | reply += "\n" + self.strings("arch", message).format( 45 | utils.escape_html(platform.architecture()[0]) 46 | ) 47 | reply += "\n" + self.strings("os", message).format( 48 | utils.escape_html(platform.system()) 49 | ) 50 | 51 | if platform.system() == "Linux": 52 | done = False 53 | try: 54 | a = open("/etc/os-release").readlines() 55 | b = { 56 | line.split("=")[0]: line.split("=")[1].strip().strip('"') 57 | for line in a 58 | } 59 | reply += "\n" + self.strings("distro", message).format( 60 | utils.escape_html(b["PRETTY_NAME"]) 61 | ) 62 | done = True 63 | except FileNotFoundError: 64 | ftg_type = "Android (Termux)" 65 | getprop = shutil.which("getprop") 66 | if getprop is not None: 67 | sdk = await asyncio.create_subprocess_exec( 68 | getprop, "ro.build.version.sdk", stdout=asyncio.subprocess.PIPE 69 | ) 70 | ver = await asyncio.create_subprocess_exec( 71 | getprop, 72 | "ro.build.version.release", 73 | stdout=asyncio.subprocess.PIPE, 74 | ) 75 | sec = await asyncio.create_subprocess_exec( 76 | getprop, 77 | "ro.build.version.security_patch", 78 | stdout=asyncio.subprocess.PIPE, 79 | ) 80 | sdks, unused = await sdk.communicate() 81 | vers, unused = await ver.communicate() 82 | secs, unused = await sec.communicate() 83 | if ( 84 | sdk.returncode == 0 85 | and ver.returncode == 0 86 | and sec.returncode == 0 87 | ): 88 | reply += "\n" + self.strings("android_sdk", message).format( 89 | sdks.decode("utf-8").strip() 90 | ) 91 | reply += "\n" + self.strings("android_ver", message).format( 92 | vers.decode("utf-8").strip() 93 | ) 94 | reply += "\n" + self.strings("android_patch", message).format( 95 | secs.decode("utf-8").strip() 96 | ) 97 | done = True 98 | if not done: 99 | reply += "\n" + self.strings("unknown_distro", message) 100 | reply += "\n" + self.strings("python_version", message).format( 101 | utils.escape_html(sys.version) 102 | ) 103 | reply += "\n" + self.strings("telethon_version", message).format( 104 | utils.escape_html(telethon.__version__) 105 | ) 106 | if "DYNO" in os.environ: 107 | ftg_type = "Heroku" 108 | else: 109 | reply += "\n" + self.strings("git_version", message).format( 110 | os.popen( 111 | f'cd {utils.get_base_dir()[:-17]} && git show -s --format="%h %cd"' 112 | ).read()[:-7] 113 | ) 114 | if "LAVHOST" in os.environ: 115 | reply += ( 116 | "\n" 117 | + "FTG Type: " 118 | + f"lavHost {os.getenv('LAVHOST')} (@lavHost)" 119 | ) 120 | else: 121 | reply += "\n" + self.strings("ftg_type", message).format(ftg_type) 122 | await utils.answer(message, reply) 123 | -------------------------------------------------------------------------------- /captcha.py: -------------------------------------------------------------------------------- 1 | # Coded by D4n13l3k00 # 2 | # t.me/D4n13l3k00 # 3 | # This code under AGPL-3.0 # 4 | 5 | # requires: aiohttp pydantic 6 | 7 | import asyncio 8 | import io 9 | import logging 10 | from typing import List 11 | import aiohttp 12 | import pydantic 13 | import telethon 14 | from telethon import types 15 | from telethon.events import ChatAction 16 | from telethon.tl.functions.channels import EditBannedRequest 17 | from telethon.tl.types import ChatBannedRights 18 | 19 | from .. import loader, utils 20 | 21 | 22 | @loader.tds 23 | class CaptchaMod(loader.Module): 24 | "Captcha for chats" 25 | 26 | strings = { 27 | "name": "Captcha", 28 | "pls_pass_captcha": 'Хэй, пройди капчу! У тебя одна попытка\nИначе получишь бан на 5 минут!', 29 | "captcha_status": "[Capthca] {}", 30 | } 31 | 32 | class CUserModel(pydantic.BaseModel): 33 | chat: int 34 | user: int 35 | message: int 36 | answer: str 37 | 38 | async def client_ready(self, _, db): 39 | self.db = db 40 | self.log = logging.getLogger(__name__) 41 | self._db = "CaptchaMod" 42 | self.locked_users: List[self.CUserModel] = [] 43 | 44 | async def watcher(self, m): 45 | "Watcher" 46 | client: telethon.TelegramClient = m.client 47 | if isinstance(m, ChatAction.Event): 48 | if m.chat_id not in self.db.get(self._db, "chats", []): 49 | return 50 | if m.user_added or m.user_joined: 51 | users = [i.id for i in m.users] 52 | for u in users: 53 | _u = await client.get_entity(u) 54 | if _u.bot: 55 | continue 56 | async with aiohttp.ClientSession() as s, s.get( 57 | "https://api.d4n13l3k00.ru/captcha/generate" 58 | ) as r: 59 | answer = r.headers["Captcha-Code"] 60 | im = io.BytesIO(await r.read()) 61 | im.name = "@DekFTGModules_catpcha.png" 62 | m = await client.send_file( 63 | m.chat, 64 | im, 65 | caption=self.strings("pls_pass_captcha").format(u), 66 | ) 67 | self.locked_users.append( 68 | self.CUserModel( 69 | chat=m.chat_id, user=u, message=m.id, answer=answer 70 | ) 71 | ) 72 | await asyncio.sleep(60) 73 | l: List[self.CUserModel] = list( 74 | filter( 75 | lambda x: x.chat == m.chat_id and x.user in users, 76 | self.locked_users, 77 | ) 78 | ) 79 | if l: 80 | for u in l: 81 | self.locked_users.remove(u) 82 | await ( 83 | await client.get_messages(u.chat, ids=u.message) 84 | ).delete() 85 | await client( 86 | EditBannedRequest( 87 | u.chat, 88 | u.user, 89 | ChatBannedRights(until_date=None, view_messages=True), 90 | ) 91 | ) 92 | elif m.user_kicked or m.user_left: 93 | users = [i.id for i in m.users] 94 | for u in users: 95 | l: List[self.CUserModel] = list( 96 | filter( 97 | lambda x: x.chat == m.chat_id and x.user == u, 98 | self.locked_users, 99 | ) 100 | ) 101 | if l: 102 | ntt = l[0] 103 | self.locked_users.remove(ntt) 104 | return 105 | 106 | if isinstance(m, types.Message): 107 | client: telethon.TelegramClient = m.client 108 | l: List[self.CUserModel] = list( 109 | filter( 110 | lambda x: x.chat == m.chat_id and x.user == m.sender_id, 111 | self.locked_users, 112 | ) 113 | ) 114 | if l: 115 | ntt = l[0] 116 | self.locked_users.remove(ntt) 117 | await (await client.get_messages(ntt.chat, ids=ntt.message)).delete() 118 | await m.delete() 119 | if ntt.answer.lower() != m.raw_text.lower(): 120 | await client( 121 | EditBannedRequest( 122 | ntt.chat, 123 | ntt.user, 124 | ChatBannedRights(until_date=None, view_messages=True), 125 | ) 126 | ) 127 | 128 | async def swcaptchacmd(self, m: types.Message): 129 | "Turn on/off captha in chat" 130 | l: list = self.db.get(self._db, "chats", []) 131 | if m.chat_id in l: 132 | l.remove(m.chat_id) 133 | self.db.set(self._db, "chats", l) 134 | return await utils.answer(m, self.strings("captcha_status").format("OFF")) 135 | l.append(m.chat_id) 136 | self.db.set(self._db, "chats", l) 137 | await utils.answer(m, self.strings("captcha_status").format("ON")) 138 | -------------------------------------------------------------------------------- /GitUploader.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # GitHub File Uploader 3 | # Copyright (C) 2020 utya @unxho & wardsenz @azeronde 4 | 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | from .. import loader, utils 18 | import logging 19 | import base64 20 | import os 21 | import requests 22 | import json 23 | from requests.exceptions import MissingSchema, ChunkedEncodingError 24 | 25 | logger = logging.getLogger(__name__) 26 | 27 | 28 | def register(cb): 29 | cb(GitaddMod()) 30 | 31 | 32 | @loader.tds 33 | class GitaddMod(loader.Module): 34 | """Загружает файлы на репозиторий GitHub""" 35 | 36 | strings = { 37 | "name": "GitUploader", 38 | "reply_to_file": "Ответьте на файл", 39 | "error_file": "Формат не поддерживается", 40 | "connection_error": "Ошибка соединения", 41 | "repo_error": "Ошибка репозитория", 42 | "token_error": "Ошибка токена", 43 | "exist_422": "Не удалось загрузить файл. Возможная причина: файл с таким названием уже существует в репозитории.", 44 | "cfg_token": "Токен GitHub", 45 | "token_not_found": "Токен не найден", 46 | "username_not_found": "Имя пользователя GitHub не указано", 47 | "repo_not_found": "Репозиторий не указан", 48 | "cfg_gh_user": "Имя пользователя на GitHub", 49 | "cfg_gh_repo": "Репозиторий, куда нужно загружать модули", 50 | } 51 | 52 | def __init__(self): 53 | self.config = loader.ModuleConfig( 54 | "GH_TOKEN", 55 | "TOKEN", 56 | lambda m: self.strings("cfg_token", m), 57 | "GH_USERNAME", 58 | "USERNAME", 59 | lambda m: self.strings("cfg_gh_user", m), 60 | "GH_REPO", 61 | "REPOSITORY", 62 | lambda m: self.strings("cfg_gh_repo", m), 63 | ) 64 | 65 | async def client_ready(self, client, db): 66 | self.client = client 67 | 68 | @loader.owner 69 | async def gitaddcmd(self, message): 70 | if self.config["GH_TOKEN"] == "TOKEN": 71 | await utils.answer(message, self.strings("token_not_found", message)) 72 | return 73 | if self.config["GH_USERNAME"] == "USERNAME": 74 | await utils.answer(message, self.strings("username_not_found", message)) 75 | return 76 | if self.config["GH_REPO"] == "REPOSITORY": 77 | await utils.answer(message, self.strings("repo_not_found", message)) 78 | return 79 | reply = await message.get_reply_message() 80 | if not reply: 81 | await utils.answer(message, self.strings("reply_to_file", message)) 82 | return 83 | media = reply.media 84 | if not media: 85 | await utils.answer(message, self.strings("reply_to_file", message)) 86 | return 87 | try: 88 | fname = (reply.media.document.attributes[0]).file_name 89 | except AttributeError: 90 | await utils.answer(message, self.strings("error_file", message)) 91 | return 92 | try: 93 | file = await message.client.download_file(media) 94 | encoded_string = base64.b64encode(file) 95 | stout = encoded_string.decode("utf-8") 96 | TOKEN = self.config["GH_TOKEN"] 97 | USERNAME = self.config["GH_USERNAME"] 98 | REPO = self.config["GH_REPO"] 99 | # url = f'{self.config["GH_REPO"]}{fname}' 100 | url = f"https://api.github.com/repos/{USERNAME}/{REPO}/contents/{fname}" 101 | head = { 102 | "Authorization": f"token {TOKEN}", 103 | "Accept": "application/vnd.github.v3+json", 104 | } 105 | git_data = '{"message": "Upload file", "content":' + '"' + stout + '"' + "}" 106 | r = requests.put(url, headers=head, data=git_data) 107 | if int(r.status_code) == 201: 108 | uploaded_to = f"https://github.com/{USERNAME}/{REPO}" 109 | uploaded_to_raw = uploaded_to + f"/raw/master/{fname}" 110 | await utils.answer( 111 | message, 112 | f"Файл {fname} успешно загружен на репозиторий!\n\nПрямая ссылка: {uploaded_to_raw}", 113 | ) 114 | return 115 | elif int(r.status_code) == 422: 116 | await utils.answer(message, self.strings("exist_422", message)) 117 | return 118 | else: 119 | json_resp = json.loads(r.text) 120 | git_resp = json_resp["message"] 121 | await utils.answer( 122 | message, 123 | f"Произошла неизвестная ошибка! Ответ сервера:\n {git_resp}", 124 | ) 125 | return 126 | except ConnectionError: 127 | await utils.answer(message, self.strings("connection_error", message)) 128 | return 129 | except MissingSchema: 130 | await utils.answer(message, self.strings("repo_error", message)) 131 | return 132 | except ChunkedEncodingError: 133 | await utils.answer(message, self.strings("token_error", message)) 134 | return 135 | -------------------------------------------------------------------------------- /notes.py: -------------------------------------------------------------------------------- 1 | # Friendly Telegram (telegram userbot) 2 | # Copyright (C) 2018-2019 The Authors 3 | 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU Affero General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU Affero General Public License for more details. 13 | 14 | # You should have received a copy of the GNU Affero General Public License 15 | # along with this program. If not, see . 16 | 17 | import logging 18 | 19 | from .. import loader, utils 20 | 21 | logger = logging.getLogger("friendly-telegram.modules.notes") 22 | 23 | 24 | @loader.tds 25 | class NotesMod(loader.Module): 26 | """Stores global notes (aka snips)""" 27 | 28 | strings = { 29 | "name": "Notes", 30 | "what_note": "Какую заметку нужно показать?", 31 | "no_note": "Заметка не найдена", 32 | "save_what": "А что сохранить?", 33 | "what_name": "А как будет называться заметка?", 34 | "saved": "Заметка сохранена как: {}", 35 | "notes_header": "Сохранённые заметки:\n\n", 36 | "notes_item": " {}", 37 | "delnote_args": "А какую заметку нужно удалить?", 38 | "delnote_done": "Заметка удалена!", 39 | "delnotes_none": "А заметок-то нету...", 40 | "delnotes_done": "ВСЕ ЗАМЕТКИ УДАЛЕНЫ", 41 | "notes_none": "А заметок-то нету...", 42 | } 43 | 44 | async def findnotecmd(self, message): 45 | """Gets the note specified""" 46 | args = utils.get_args(message) 47 | if not args: 48 | await utils.answer(message, self.strings("what_note", message)) 49 | return 50 | asset_id = self._db.get("friendly-telegram.modules.notes", "notes", {}).get( 51 | args[0], None 52 | ) 53 | logger.debug(asset_id) 54 | asset = await self._db.fetch_asset(asset_id) if asset_id is not None else None 55 | if asset is None: 56 | self.del_note(args[0]) 57 | await utils.answer(message, self.strings("no_note", message)) 58 | return 59 | link = "https://t.me/c/{}/{}".format(asset.chat.id, asset.id) 60 | await message.edit( 61 | f'Заметка "{args[0]}" находится здесь.' 62 | ) 63 | 64 | async def notecmd(self, message): 65 | """Gets the note specified""" 66 | args = utils.get_args(message) 67 | if not args: 68 | await utils.answer(message, self.strings("what_note", message)) 69 | return 70 | asset_id = self._db.get("friendly-telegram.modules.notes", "notes", {}).get( 71 | args[0], None 72 | ) 73 | logger.debug(asset_id) 74 | asset = await self._db.fetch_asset(asset_id) if asset_id is not None else None 75 | if asset is None: 76 | self.del_note(args[0]) 77 | await utils.answer(message, self.strings("no_note", message)) 78 | return 79 | await message.delete() 80 | await message.client.send_message( 81 | message.to_id, 82 | await self._db.fetch_asset(asset_id), 83 | reply_to=await message.get_reply_message(), 84 | ) 85 | 86 | async def delallnotescmd(self, message): 87 | """Deletes all the saved notes""" 88 | if not self._db.get("friendly-telegram.modules.notes", "notes", {}): 89 | await utils.answer(message, self.strings("delnotes_none", message)) 90 | return 91 | self._db.get("friendly-telegram.modules.notes", "notes", {}).clear() 92 | await utils.answer(message, self.strings("delnotes_done", message)) 93 | 94 | async def savecmd(self, message): 95 | """Save a new note. Must be used in reply with one parameter (note name)""" 96 | args = utils.get_args(message) 97 | if not args: 98 | await utils.answer(message, self.strings("what_name", message)) 99 | return 100 | if message.is_reply: 101 | target = await message.get_reply_message() 102 | elif len(args) < 2: 103 | await utils.answer(message, self.strings("save_what", message)) 104 | return 105 | else: 106 | message.entities = None 107 | message.message = args[1] 108 | target = message 109 | logger.debug(target.message) 110 | asset_id = await self._db.store_asset(target) 111 | self._db.set( 112 | "friendly-telegram.modules.notes", 113 | "notes", 114 | { 115 | **self._db.get("friendly-telegram.modules.notes", "notes", {}), 116 | args[0]: asset_id, 117 | }, 118 | ) 119 | await utils.answer(message, str(self.strings("saved", message)).format(args[0])) 120 | 121 | async def delnotecmd(self, message): 122 | """Deletes a note, specified by note name""" 123 | args = utils.get_args(message) 124 | if not args: 125 | await utils.answer(message, self.strings("delnote_args", message)) 126 | self.del_note(args[0]) 127 | await utils.answer(message, self.strings("delnote_done", message)) 128 | 129 | def del_note(self, note): 130 | old = self._db.get("friendly-telegram.modules.notes", "notes", {}) 131 | try: 132 | del old[note] 133 | except KeyError: 134 | pass 135 | else: 136 | self._db.set("friendly-telegram.modules.notes", "notes", old) 137 | 138 | async def notescmd(self, message): 139 | """List the saved notes""" 140 | if not self._db.get("friendly-telegram.modules.notes", "notes", {}): 141 | await utils.answer(message, self.strings("notes_none", message)) 142 | return 143 | await utils.answer( 144 | message, 145 | self.strings("notes_header", message) 146 | + "\n".join( 147 | self.strings("notes_item", message).format(key) 148 | for key in self._db.get("friendly-telegram.modules.notes", "notes", {}) 149 | ), 150 | ) 151 | 152 | async def client_ready(self, client, db): 153 | self._db = db 154 | -------------------------------------------------------------------------------- /lovemagic.py: -------------------------------------------------------------------------------- 1 | import random 2 | from .. import utils, loader 3 | from asyncio import sleep 4 | 5 | 6 | @loader.tds 7 | class ILYMod(loader.Module): 8 | """Famous TikTok hearts animation implemented in FTG""" 9 | 10 | strings = {"name": "LoveMagic"} 11 | 12 | async def ilycmd(self, message: "telethon.tl.types.Message") -> None: 13 | """This famous TikTok animation...""" 14 | if not message.out: 15 | message = await message.respond("ily") 16 | 17 | arr = ["❤️", "🧡", "💛", "💚", "💙", "💜", "🤎", "🖤", "💖"] 18 | h = "🤍" 19 | first_block = "" 20 | for i in "".join( 21 | [ 22 | h * 9, 23 | "\n", 24 | h * 2, 25 | arr[0] * 2, 26 | h, 27 | arr[0] * 2, 28 | h * 2, 29 | "\n", 30 | h, 31 | arr[0] * 7, 32 | h, 33 | "\n", 34 | h, 35 | arr[0] * 7, 36 | h, 37 | "\n", 38 | h, 39 | arr[0] * 7, 40 | h, 41 | "\n", 42 | h * 2, 43 | arr[0] * 5, 44 | h * 2, 45 | "\n", 46 | h * 3, 47 | arr[0] * 3, 48 | h * 3, 49 | "\n", 50 | h * 4, 51 | arr[0], 52 | h * 4, 53 | ] 54 | ).split("\n"): 55 | first_block += i + "\n" 56 | await message.edit(first_block) 57 | await sleep(0.1) 58 | for i in arr: 59 | await message.edit( 60 | "".join( 61 | [ 62 | h * 9, 63 | "\n", 64 | h * 2, 65 | i * 2, 66 | h, 67 | i * 2, 68 | h * 2, 69 | "\n", 70 | h, 71 | i * 7, 72 | h, 73 | "\n", 74 | h, 75 | i * 7, 76 | h, 77 | "\n", 78 | h, 79 | i * 7, 80 | h, 81 | "\n", 82 | h * 2, 83 | i * 5, 84 | h * 2, 85 | "\n", 86 | h * 3, 87 | i * 3, 88 | h * 3, 89 | "\n", 90 | h * 4, 91 | i, 92 | h * 4, 93 | "\n", 94 | h * 9, 95 | ] 96 | ) 97 | ) 98 | await sleep(0.2) 99 | for _ in range(8): 100 | rand = random.choices(arr, k=34) 101 | await message.edit( 102 | "".join( 103 | [ 104 | h * 9, 105 | "\n", 106 | h * 2, 107 | rand[0], 108 | rand[1], 109 | h, 110 | rand[2], 111 | rand[3], 112 | h * 2, 113 | "\n", 114 | h, 115 | rand[4], 116 | rand[5], 117 | rand[6], 118 | rand[7], 119 | rand[8], 120 | rand[9], 121 | rand[10], 122 | h, 123 | "\n", 124 | h, 125 | rand[11], 126 | rand[12], 127 | rand[13], 128 | rand[14], 129 | rand[15], 130 | rand[16], 131 | rand[17], 132 | h, 133 | "\n", 134 | h, 135 | rand[18], 136 | rand[19], 137 | rand[20], 138 | rand[21], 139 | rand[22], 140 | rand[23], 141 | rand[24], 142 | h, 143 | "\n", 144 | h * 2, 145 | rand[25], 146 | rand[26], 147 | rand[27], 148 | rand[28], 149 | rand[29], 150 | h * 2, 151 | "\n", 152 | h * 3, 153 | rand[30], 154 | rand[31], 155 | rand[32], 156 | h * 3, 157 | "\n", 158 | h * 4, 159 | rand[33], 160 | h * 4, 161 | "\n", 162 | h * 9, 163 | ] 164 | ) 165 | ) 166 | await sleep(0.2) 167 | fourth = "".join( 168 | [ 169 | h * 9, 170 | "\n", 171 | h * 2, 172 | arr[0] * 2, 173 | h, 174 | arr[0] * 2, 175 | h * 2, 176 | "\n", 177 | h, 178 | arr[0] * 7, 179 | h, 180 | "\n", 181 | h, 182 | arr[0] * 7, 183 | h, 184 | "\n", 185 | h, 186 | arr[0] * 7, 187 | h, 188 | "\n", 189 | h * 2, 190 | arr[0] * 5, 191 | h * 2, 192 | "\n", 193 | h * 3, 194 | arr[0] * 3, 195 | h * 3, 196 | "\n", 197 | h * 4, 198 | arr[0], 199 | h * 4, 200 | "\n", 201 | h * 9, 202 | ] 203 | ) 204 | await message.edit(fourth) 205 | for _ in range(47): 206 | fourth = fourth.replace("🤍", "❤️", 1) 207 | await message.edit(fourth) 208 | await sleep(0.07) 209 | for i in range(8): 210 | await message.edit((arr[0] * (8 - i) + "\n") * (8 - i)) 211 | await sleep(0.3) 212 | for i in ["I", "I ❤️", "I ❤️ U", "I ❤️ U!"]: 213 | await message.edit(f"{i}") 214 | await sleep(0.2) 215 | -------------------------------------------------------------------------------- /chat_voice_mod.py: -------------------------------------------------------------------------------- 1 | # Coded by D4n13l3k00 # 2 | # t.me/D4n13l3k00 # 3 | # This code under AGPL-3.0 # 4 | 5 | # requires: py-tgcalls 6 | 7 | from typing import * 8 | 9 | import pytgcalls 10 | from pytgcalls import PyTgCalls, StreamType 11 | from pytgcalls.types.input_stream import AudioPiped, AudioVideoPiped 12 | from pytgcalls.types.input_stream.quality import HighQualityAudio, HighQualityVideo 13 | from telethon import types 14 | 15 | from .. import loader, utils 16 | 17 | 18 | @loader.tds 19 | class ChatVoiceMod(loader.Module): 20 | """Module for working with voicechat""" 21 | 22 | strings = { 23 | "name": "ChatVoiceMod", 24 | "downloading": "[ChatVoiceMod] Downloading...", 25 | "playing": "[ChatVoiceMod] Playing...", 26 | "notjoined": "[ChatVoiceMod] You are not joined", 27 | "stop": "[ChatVoiceMod] Playing stopped!", 28 | "leave": "[ChatVoiceMod] Leaved!", 29 | "pause": "[ChatVoiceMod] Paused!", 30 | "resume": "[ChatVoiceMod] Resumed!", 31 | "mute": "[ChatVoiceMod] Muted!", 32 | "unmute": "[ChatVoiceMod] Unmuted!", 33 | "error": "[ChatVoiceMod] Error: {}", 34 | "noargs": "[ChatVoiceMod] No args", 35 | } 36 | 37 | async def client_ready(self, client, _): 38 | self.client = client 39 | self.call = PyTgCalls(client) 40 | 41 | @self.call.on_stream_end() 42 | async def _h(client: PyTgCalls, update): 43 | try: 44 | await self.call.leave_group_call(update.chat_id) 45 | except Exception as e: 46 | await self.client.send_message( 47 | update.chat_id, self.strings("error").format(str(e)) 48 | ) 49 | 50 | await self.call.start() 51 | 52 | async def cplayvcmd(self, m: types.Message): 53 | " - Play video in voice chat" 54 | try: 55 | reply = await m.get_reply_message() 56 | path = utils.get_args_raw(m) 57 | chat = m.chat.id 58 | if not path: 59 | if not reply: 60 | return await utils.answer(m, self.strings("noargs")) 61 | m = await utils.answer(m, self.strings("downloading")) 62 | path = await reply.download_media() 63 | try: 64 | self.call.get_active_call(chat) 65 | await self.call.leave_group_call(chat) 66 | except pytgcalls.exceptions.GroupCallNotFound: 67 | pass 68 | await self.call.join_group_call( 69 | chat, 70 | AudioVideoPiped( 71 | path, 72 | HighQualityAudio(), 73 | HighQualityVideo(), 74 | ), 75 | stream_type=StreamType().pulse_stream, 76 | ) 77 | await utils.answer(m, self.strings("playing")) 78 | except Exception as e: 79 | await utils.answer(m, self.strings("error").format(str(e))) 80 | 81 | async def cplayacmd(self, m: types.Message): 82 | " - Play audio in voice chat" 83 | try: 84 | reply = await m.get_reply_message() 85 | path = utils.get_args_raw(m) 86 | chat = m.chat.id 87 | if not path: 88 | if not reply: 89 | return await utils.answer(m, self.strings("noargs")) 90 | m = await utils.answer(m, self.strings("downloading")) 91 | path = await reply.download_media() 92 | try: 93 | self.call.get_active_call(chat) 94 | await self.call.leave_group_call(chat) 95 | except pytgcalls.exceptions.GroupCallNotFound: 96 | pass 97 | await self.call.join_group_call( 98 | chat, 99 | AudioPiped( 100 | path, 101 | HighQualityAudio(), 102 | ), 103 | stream_type=StreamType().pulse_stream, 104 | ) 105 | await utils.answer(m, self.strings("playing")) 106 | except Exception as e: 107 | await utils.answer(m, self.strings("error").format(str(e))) 108 | 109 | async def cleavecmd(self, m: types.Message): 110 | "Leave" 111 | try: 112 | self.call.get_active_call(m.chat.id) 113 | await self.call.leave_group_call(m.chat.id) 114 | await utils.answer(m, self.strings("leave")) 115 | except pytgcalls.exceptions.GroupCallNotFound: 116 | await utils.answer(m, self.strings("notjoined")) 117 | except Exception as e: 118 | await utils.answer(m, self.strings("error").format(str(e))) 119 | 120 | async def cmutecmd(self, m: types.Message): 121 | "Mute" 122 | try: 123 | self.call.get_active_call(m.chat.id) 124 | await self.call.mute_stream(m.chat.id) 125 | await utils.answer(m, self.strings("mute")) 126 | except pytgcalls.exceptions.GroupCallNotFound: 127 | await utils.answer(m, self.strings("notjoined")) 128 | except Exception as e: 129 | await utils.answer(m, self.strings("error").format(str(e))) 130 | 131 | async def cunmutecmd(self, m: types.Message): 132 | "Unmute" 133 | try: 134 | self.call.get_active_call(m.chat.id) 135 | await self.call.unmute_stream(m.chat.id) 136 | await utils.answer(m, self.strings("unmute")) 137 | except pytgcalls.exceptions.GroupCallNotFound: 138 | await utils.answer(m, self.strings("notjoined")) 139 | except Exception as e: 140 | await utils.answer(m, self.strings("error").format(str(e))) 141 | 142 | async def cpausecmd(self, m: types.Message): 143 | "Pause" 144 | try: 145 | self.call.get_active_call(m.chat.id) 146 | await self.call.pause_stream(m.chat.id) 147 | await utils.answer(m, self.strings("pause")) 148 | except pytgcalls.exceptions.GroupCallNotFound: 149 | await utils.answer(m, self.strings("notjoined")) 150 | except Exception as e: 151 | await utils.answer(m, self.strings("error").format(str(e))) 152 | 153 | async def cresumecmd(self, m: types.Message): 154 | "Resume" 155 | try: 156 | self.call.get_active_call(m.chat.id) 157 | await self.call.resume_stream(m.chat.id) 158 | await utils.answer(m, self.strings("resume")) 159 | except pytgcalls.exceptions.GroupCallNotFound: 160 | await utils.answer(m, self.strings("notjoined")) 161 | except Exception as e: 162 | await utils.answer(m, self.strings("error").format(str(e))) 163 | -------------------------------------------------------------------------------- /downloader.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Module author: @GovnoCodules, @ftgmodulesbyfl1yd 4 | 5 | import io 6 | import os 7 | from asyncio import sleep 8 | 9 | from requests import get 10 | from telethon import events 11 | from telethon import functions 12 | from telethon.errors.rpcerrorlist import YouBlockedUserError 13 | from telethon.tl.types import MessageEntityUrl, MessageEntityTextUrl 14 | 15 | from .. import loader, utils 16 | 17 | 18 | @loader.tds 19 | class DownloaderMod(loader.Module): 20 | """Downloader module""" 21 | 22 | strings = {"name": "Downloader"} 23 | 24 | async def dlrcmd(self, message): 25 | """.dlr - download file to server""" 26 | name = utils.get_args_raw(message) 27 | reply = await message.get_reply_message() 28 | if reply: 29 | await message.edit("Downloading...") 30 | if reply.text: 31 | text = reply.text 32 | fname = f"{name or message.id + reply.id}.txt" 33 | with open(fname, "w") as file: 34 | file.write(text) 35 | else: 36 | ext = reply.file.ext 37 | fname = f"{name or message.id + reply.id}{ext}" 38 | await message.client.download_media(reply, fname) 39 | await message.edit( 40 | f"FIle saved as: {fname}.\n\nYou " 41 | f"can send it with command: " 42 | f".ulf {fname}." 43 | ) 44 | else: 45 | return await message.edit("There is no reply") 46 | 47 | async def ulfcmd(self, message): 48 | """.ulf send file from server 49 | - Delete file after sending""" 50 | name = utils.get_args_raw(message) 51 | d = "d " in name 52 | if not name: 53 | return await message.edit("No args") 54 | try: 55 | name = name.replace("d ", "") 56 | await message.edit(f"Sending {name}...") 57 | if d: 58 | await message.client.send_file(message.to_id, f"{name}") 59 | await message.edit( 60 | f"Sending {name}... Success!\nDeleting " 61 | f"{name}..." 62 | ) 63 | os.remove(name) 64 | await message.edit( 65 | f"Sending {name}... Deleting!\nУдаляем " 66 | f"{name}... Success!" 67 | ) 68 | await sleep(0.5) 69 | else: 70 | await message.client.send_file(message.to_id, name) 71 | except Exception: 72 | return await message.edit("File does not exist") 73 | await message.delete() 74 | 75 | async def dltiktokcmd(self, message): 76 | """TikTok video downloader""" 77 | chat = "@ttsavebot" 78 | reply = await message.get_reply_message() 79 | async with message.client.conversation(chat) as conv: 80 | text = utils.get_args_raw(message) 81 | if reply: 82 | text = await message.get_reply_message() 83 | await message.edit("Downloading...") 84 | try: 85 | response = conv.wait_event( 86 | events.NewMessage(incoming=True, from_users=1087584961) 87 | ) 88 | response2 = conv.wait_event( 89 | events.NewMessage(incoming=True, from_users=1087584961) 90 | ) 91 | response3 = conv.wait_event( 92 | events.NewMessage(incoming=True, from_users=1087584961) 93 | ) 94 | mm = await message.client.send_message(chat, text) 95 | response = await response 96 | response2 = await response2 97 | response3 = await response3 98 | await mm.delete() 99 | except YouBlockedUserError: 100 | await message.edit("Разблокируй @ttsavebot") 101 | return 102 | await message.client.send_file( 103 | message.to_id, response3.media, reply_to=reply 104 | ) 105 | await message.delete() 106 | await message.client( 107 | functions.messages.DeleteHistoryRequest( 108 | peer="ttsavebot", max_id=0, just_clear=False, revoke=True 109 | ) 110 | ) 111 | 112 | async def dlfilecmd(self, message): 113 | """File downloader (small files)""" 114 | await downloading(message) 115 | 116 | async def dlbigfilecmd(self, message): 117 | """File downloader (big files)""" 118 | await downloading(message, True) 119 | 120 | 121 | async def downloading(message, big=False): 122 | args = utils.get_args_raw(message) 123 | reply = await message.get_reply_message() 124 | if not args: 125 | if not reply: 126 | await message.edit("There is no link!") 127 | return 128 | message = reply 129 | else: 130 | message = message 131 | 132 | if not message.entities: 133 | await message.edit("There is no link!") 134 | return 135 | 136 | urls = [] 137 | for ent in message.entities: 138 | if type(ent) in [MessageEntityUrl, MessageEntityTextUrl]: 139 | if type(ent) == MessageEntityUrl: 140 | offset = ent.offset 141 | length = ent.length 142 | url = message.raw_text[offset : offset + length] 143 | else: 144 | url = ent.url 145 | if not url.startswith("http"): 146 | url = f"http://{url}" 147 | urls.append(url) 148 | 149 | if not urls: 150 | await message.edit("There is no link!") 151 | return 152 | for url in urls: 153 | try: 154 | await message.edit("Downloading...\n" + url) 155 | fname = url.split("/")[-1] 156 | text = get(url, stream=big) 157 | if big: 158 | with open(fname, "wb") as f: 159 | for chunk in text.iter_content(1024): 160 | f.write(chunk) 161 | await message.edit("Sending...\n" + url) 162 | await message.client.send_file( 163 | message.to_id, open(fname, "rb"), reply_to=reply 164 | ) 165 | os.remove(fname) 166 | else: 167 | file = io.BytesIO(text.content) 168 | file.name = fname 169 | file.seek(0) 170 | await message.edit("Sending...\n" + url) 171 | await message.client.send_file(message.to_id, file, reply_to=reply) 172 | 173 | except Exception as e: 174 | await message.reply( 175 | "Error while downloading!\n" 176 | + url 177 | + "\n" 178 | + str(e) 179 | + "" 180 | ) 181 | 182 | await message.delete() 183 | -------------------------------------------------------------------------------- /fake_actions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Module author: @ftgmodulesbyfl1yd, @GovnoCodules 4 | 5 | from asyncio import sleep 6 | 7 | from telethon import functions 8 | 9 | from random import randint 10 | from .. import loader, utils 11 | 12 | 13 | @loader.tds 14 | class FakeMod(loader.Module): 15 | """Imitates your actions""" 16 | 17 | strings = {"name": "Fake Actions"} 18 | 19 | async def typecmd(self, message): 20 | """Imitates typing""" 21 | activity_time = utils.get_args(message) 22 | await message.delete() 23 | if activity_time: 24 | try: 25 | async with message.client.action(message.chat_id, "typing"): 26 | await sleep(int(activity_time[0])) 27 | except BaseException: 28 | return 29 | else: 30 | try: 31 | async with message.client.action(message.chat_id, "typing"): 32 | await sleep(randint(30, 60)) 33 | except BaseException: 34 | return 35 | 36 | async def voicecmd(self, message): 37 | """Imitates sending voices""" 38 | activity_time = utils.get_args(message) 39 | await message.delete() 40 | if activity_time: 41 | try: 42 | async with message.client.action(message.chat_id, "voice"): 43 | await sleep(int(activity_time[0])) 44 | except BaseException: 45 | return 46 | else: 47 | try: 48 | async with message.client.action(message.chat_id, "voice"): 49 | await sleep(randint(30, 60)) 50 | except BaseException: 51 | return 52 | 53 | async def gamecmd(self, message): 54 | """Imitates your game activity""" 55 | activity_time = utils.get_args(message) 56 | await message.delete() 57 | if activity_time: 58 | try: 59 | async with message.client.action(message.chat_id, "game"): 60 | await sleep(int(activity_time[0])) 61 | except BaseException: 62 | return 63 | else: 64 | try: 65 | async with message.client.action(message.chat_id, "game"): 66 | await sleep(randint(30, 60)) 67 | except BaseException: 68 | return 69 | 70 | async def videocmd(self, message): 71 | """Imitates sending video""" 72 | activity_time = utils.get_args(message) 73 | await message.delete() 74 | if activity_time: 75 | try: 76 | async with message.client.action(message.chat_id, "video"): 77 | await sleep(int(activity_time[0])) 78 | except BaseException: 79 | return 80 | else: 81 | try: 82 | async with message.client.action(message.chat_id, "video"): 83 | await sleep(randint(30, 60)) 84 | except BaseException: 85 | return 86 | 87 | async def photocmd(self, message): 88 | """Imitates sending photo""" 89 | activity_time = utils.get_args(message) 90 | await message.delete() 91 | if activity_time: 92 | try: 93 | async with message.client.action(message.chat_id, "photo"): 94 | await sleep(int(activity_time[0])) 95 | except BaseException: 96 | return 97 | else: 98 | try: 99 | async with message.client.action(message.chat_id, "photo"): 100 | await sleep(randint(30, 60)) 101 | except BaseException: 102 | return 103 | 104 | async def documentcmd(self, message): 105 | """Imitates sending document""" 106 | activity_time = utils.get_args(message) 107 | await message.delete() 108 | if activity_time: 109 | try: 110 | async with message.client.action(message.chat_id, "document"): 111 | await sleep(int(activity_time[0])) 112 | except BaseException: 113 | return 114 | else: 115 | try: 116 | async with message.client.action(message.chat_id, "document"): 117 | await sleep(randint(30, 60)) 118 | except BaseException: 119 | return 120 | 121 | async def locationcmd(self, message): 122 | """Imitates sending location""" 123 | activity_time = utils.get_args(message) 124 | await message.delete() 125 | if activity_time: 126 | try: 127 | async with message.client.action(message.chat_id, "location"): 128 | await sleep(int(activity_time[0])) 129 | except BaseException: 130 | return 131 | else: 132 | try: 133 | async with message.client.action(message.chat_id, "location"): 134 | await sleep(randint(30, 60)) 135 | except BaseException: 136 | return 137 | 138 | async def recordvideocmd(self, message): 139 | """Imitates recording video""" 140 | activity_time = utils.get_args(message) 141 | await message.delete() 142 | if activity_time: 143 | try: 144 | async with message.client.action(message.chat_id, "record-video"): 145 | await sleep(int(activity_time[0])) 146 | except BaseException: 147 | return 148 | else: 149 | try: 150 | async with message.client.action(message.chat_id, "record-video"): 151 | await sleep(randint(30, 60)) 152 | except BaseException: 153 | return 154 | 155 | async def recordvoicecmd(self, message): 156 | """Imitates recording voice""" 157 | activity_time = utils.get_args(message) 158 | await message.delete() 159 | if activity_time: 160 | try: 161 | async with message.client.action(message.chat_id, "record-audio"): 162 | await sleep(int(activity_time[0])) 163 | except BaseException: 164 | return 165 | else: 166 | try: 167 | async with message.client.action(message.chat_id, "record-audio"): 168 | await sleep(randint(30, 60)) 169 | except BaseException: 170 | return 171 | 172 | async def recordroundcmd(self, message): 173 | """Imitates recording round video""" 174 | activity_time = utils.get_args(message) 175 | await message.delete() 176 | if activity_time: 177 | try: 178 | async with message.client.action(message.chat_id, "record-round"): 179 | await sleep(int(activity_time[0])) 180 | except BaseException: 181 | return 182 | else: 183 | try: 184 | async with message.client.action(message.chat_id, "record-round"): 185 | await sleep(randint(30, 60)) 186 | except BaseException: 187 | return 188 | 189 | async def scrncmd(self, message): 190 | """Screenshot notification (Only PM)""" 191 | a = 1 192 | r = utils.get_args(message) 193 | if r and r[0].isdigit(): 194 | a = int(r[0]) 195 | for _ in range(a): 196 | await message.client( 197 | functions.messages.SendScreenshotNotificationRequest( 198 | peer=message.to_id, reply_to_msg_id=message.id 199 | ) 200 | ) 201 | await message.delete() 202 | -------------------------------------------------------------------------------- /zombie_users.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2019 The Raphielscape Company LLC. 2 | # 3 | # Licensed under the Raphielscape Public License, Version 1.c (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | """ 6 | Userbot module to help you manage a group 7 | """ 8 | 9 | from asyncio import sleep 10 | from os import remove 11 | 12 | from telethon.errors import ( 13 | BadRequestError, 14 | ChatAdminRequiredError, 15 | ImageProcessFailedError, 16 | PhotoCropSizeSmallError, 17 | UserAdminInvalidError, 18 | ) 19 | from telethon.errors.rpcerrorlist import UserIdInvalidError, MessageTooLongError 20 | from telethon.tl.functions.channels import ( 21 | EditAdminRequest, 22 | EditBannedRequest, 23 | EditPhotoRequest, 24 | ) 25 | from telethon.tl.functions.messages import UpdatePinnedMessageRequest 26 | from telethon.tl.types import ( 27 | ChannelParticipantsAdmins, 28 | ChatAdminRights, 29 | ChatBannedRights, 30 | MessageEntityMentionName, 31 | MessageMediaPhoto, 32 | ) 33 | 34 | from userbot import BOTLOG, BOTLOG_CHATID, CMD_HELP, bot 35 | from userbot.events import register 36 | 37 | 38 | BANNED_RIGHTS = ChatBannedRights( 39 | until_date=None, 40 | view_messages=True, 41 | send_messages=True, 42 | send_media=True, 43 | send_stickers=True, 44 | send_gifs=True, 45 | send_games=True, 46 | send_inline=True, 47 | embed_links=True, 48 | ) 49 | 50 | UNBAN_RIGHTS = ChatBannedRights( 51 | until_date=None, 52 | send_messages=None, 53 | send_media=None, 54 | send_stickers=None, 55 | send_gifs=None, 56 | send_games=None, 57 | send_inline=None, 58 | embed_links=None, 59 | ) 60 | 61 | 62 | @register(outgoing=True, pattern="^.zombies(?: |$)(.*)", groups_only=True) 63 | async def rm_deletedacc(show): 64 | """For .delusers command, list all the ghost/deleted accounts in a chat.""" 65 | if not show.is_group: 66 | await show.edit("`I don't think this is a group.`") 67 | return 68 | con = show.pattern_match.group(1).lower() 69 | del_u = 0 70 | del_status = "`No deleted accounts found, Group is cleaned as Hell`" 71 | 72 | if con != "clean": 73 | await show.edit("`Searching for zombie accounts...`") 74 | async for user in show.client.iter_participants(show.chat_id): 75 | if user.deleted: 76 | del_u += 1 77 | await sleep(1) 78 | if del_u > 0: 79 | del_status = f"Found **{del_u}** deleted account(s) in this group,\ 80 | \nclean them by using `.zombies clean`" 81 | 82 | await show.edit(del_status) 83 | return 84 | 85 | # Here laying the sanity check 86 | chat = await show.get_chat() 87 | admin = chat.admin_rights 88 | creator = chat.creator 89 | 90 | # Well 91 | if not admin and not creator: 92 | await show.edit("`I am not an admin here!`") 93 | return 94 | 95 | await show.edit("`Deleting deleted accounts...\nOh I can do that?!?!`") 96 | del_u = 0 97 | del_a = 0 98 | 99 | async for user in show.client.iter_participants(show.chat_id): 100 | if user.deleted: 101 | try: 102 | await show.client( 103 | EditBannedRequest(show.chat_id, user.id, BANNED_RIGHTS) 104 | ) 105 | except ChatAdminRequiredError: 106 | await show.edit("`I don't have ban rights in this group`") 107 | return 108 | except UserAdminInvalidError: 109 | del_u -= 1 110 | del_a += 1 111 | await show.client(EditBannedRequest(show.chat_id, user.id, UNBAN_RIGHTS)) 112 | del_u += 1 113 | 114 | if del_u > 0: 115 | del_status = f"Cleaned **{del_u}** deleted account(s)" 116 | 117 | if del_a > 0: 118 | del_status = f"Cleaned **{del_u}** deleted account(s) \ 119 | \n**{del_a}** deleted admin accounts are not removed" 120 | 121 | await show.edit(del_status) 122 | await sleep(2) 123 | await show.delete() 124 | 125 | if BOTLOG: 126 | await show.client.send_message( 127 | BOTLOG_CHATID, 128 | "#CLEANUP\n" 129 | f"Cleaned **{del_u}** deleted account(s) !!\ 130 | \nCHAT: {show.chat.title}(`{show.chat_id}`)", 131 | ) 132 | 133 | 134 | @register(outgoing=True, pattern="^.users ?(.*)", groups_only=True) 135 | async def get_users(show): 136 | """For .users command, list all of the users in a chat.""" 137 | info = await show.client.get_entity(show.chat_id) 138 | title = info.title or "this chat" 139 | mentions = "Users in {}: \n".format(title) 140 | try: 141 | if not show.pattern_match.group(1): 142 | async for user in show.client.iter_participants(show.chat_id): 143 | if not user.deleted: 144 | mentions += ( 145 | f"\n[{user.first_name}](tg://user?id={user.id}) `{user.id}`" 146 | ) 147 | else: 148 | mentions += f"\nDeleted Account `{user.id}`" 149 | else: 150 | searchq = show.pattern_match.group(1) 151 | async for user in show.client.iter_participants( 152 | show.chat_id, search=f"{searchq}" 153 | ): 154 | if not user.deleted: 155 | mentions += ( 156 | f"\n[{user.first_name}](tg://user?id={user.id}) `{user.id}`" 157 | ) 158 | else: 159 | mentions += f"\nDeleted Account `{user.id}`" 160 | except ChatAdminRequiredError as err: 161 | mentions += " " + str(err) + "\n" 162 | try: 163 | await show.edit(mentions) 164 | except MessageTooLongError: 165 | await show.edit("Damn, this is a huge group. Uploading users lists as file.") 166 | with open("userslist.txt", "w+") as file: 167 | file.write(mentions) 168 | await show.client.send_file( 169 | show.chat_id, 170 | "userslist.txt", 171 | caption="Users in {}".format(title), 172 | reply_to=show.id, 173 | ) 174 | remove("userslist.txt") 175 | 176 | 177 | async def get_user_from_event(event): 178 | """Get the user from argument or replied message.""" 179 | args = event.pattern_match.group(1).split(":", 1) 180 | extra = None 181 | if event.reply_to_msg_id and len(args) != 2: 182 | previous_message = await event.get_reply_message() 183 | user_obj = await event.client.get_entity(previous_message.from_id) 184 | extra = event.pattern_match.group(1) 185 | elif len(args[0]) > 0: 186 | user = args[0] 187 | if len(args) == 2: 188 | extra = args[1] 189 | 190 | if user.isnumeric(): 191 | user = int(user) 192 | 193 | if not user: 194 | await event.edit("`Pass the user's username, id or reply!`") 195 | return 196 | 197 | if event.message.entities is not None: 198 | probable_user_mention_entity = event.message.entities[0] 199 | 200 | if isinstance(probable_user_mention_entity, MessageEntityMentionName): 201 | user_id = probable_user_mention_entity.user_id 202 | user_obj = await event.client.get_entity(user_id) 203 | return user_obj 204 | try: 205 | user_obj = await event.client.get_entity(user) 206 | except (TypeError, ValueError) as err: 207 | await event.edit(str(err)) 208 | return None 209 | 210 | return user_obj, extra 211 | 212 | 213 | async def get_user_from_id(user, event): 214 | if isinstance(user, str): 215 | user = int(user) 216 | 217 | try: 218 | user_obj = await event.client.get_entity(user) 219 | except (TypeError, ValueError) as err: 220 | await event.edit(str(err)) 221 | return None 222 | 223 | return user_obj 224 | -------------------------------------------------------------------------------- /texttospeech.py: -------------------------------------------------------------------------------- 1 | # Friendly Telegram (telegram userbot) 2 | # module author: @anon97945 3 | 4 | # make sure to install dependencies 5 | # .terminal sudo apt install libsndfile1 gcc ffmpeg rubberband-cli -y 6 | 7 | # requires: gtts pydub soundfile pyrubberband numpy AudioSegment subprocess wave re os io 8 | 9 | import wave 10 | import re 11 | import os 12 | import sys 13 | import soundfile 14 | import pyrubberband 15 | 16 | from gtts import gTTS 17 | from io import BytesIO 18 | from .. import loader, utils 19 | from subprocess import Popen, PIPE 20 | from pydub import AudioSegment, effects 21 | 22 | 23 | async def audionormalizer(bytes_io_file, fn, fe): 24 | # return bytes_io_file, fn, fe 25 | bytes_io_file.seek(0) 26 | bytes_io_file.name = fn + fe 27 | rawsound = AudioSegment.from_file(bytes_io_file, "wav") 28 | normalizedsound = effects.normalize(rawsound) 29 | bytes_io_file.seek(0) 30 | normalizedsound.export(bytes_io_file, format="wav") 31 | bytes_io_file.name = fn + ".wav" 32 | fn, fe = os.path.splitext(bytes_io_file.name) 33 | return bytes_io_file, fn, fe 34 | 35 | 36 | async def audiohandler(bytes_io_file, fn, fe): 37 | # return bytes_io_file, fn, fe 38 | bytes_io_file.seek(0) 39 | bytes_io_file.name = fn + fe 40 | content = bytes_io_file.getvalue() 41 | cmd = [ 42 | "ffmpeg", 43 | "-y", 44 | "-i", 45 | "pipe:", 46 | "-acodec", 47 | "pcm_s16le", 48 | "-f", 49 | "wav", 50 | "-ac", 51 | "1", 52 | "pipe:", 53 | ] 54 | p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE, bufsize=-1) 55 | out, _ = p.communicate(input=content) 56 | p.stdin.close() 57 | bytes_io_file.name = fn + ".wav" 58 | fn, fe = os.path.splitext(bytes_io_file.name) 59 | return BytesIO(out), fn, fe if out.startswith(b"RIFF\xff\xff\xff") else None 60 | 61 | 62 | async def makewaves(bytes_io_file, fn, fe): 63 | # return bytes_io_file, fn, fe 64 | bytes_io_file.seek(0) 65 | bytes_io_file.name = fn + fe 66 | content = bytes_io_file.getvalue() 67 | cmd = [ 68 | "ffmpeg", 69 | "-y", 70 | "-i", 71 | "pipe:", 72 | "-c:a", 73 | "libopus", 74 | "-f", 75 | "opus", 76 | "-ac", 77 | "2", 78 | "pipe:", 79 | ] 80 | p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE, bufsize=-1) 81 | out, _ = p.communicate(input=content) 82 | p.stdin.close() 83 | bytes_io_file.name = fn + ".opus" 84 | fn, fe = os.path.splitext(bytes_io_file.name) 85 | return BytesIO(out), fn, fe 86 | 87 | 88 | def represents_speed(s): 89 | try: 90 | float(s) 91 | if 0.25 <= float(s) <= 3: 92 | return True 93 | else: 94 | return False 95 | except ValueError: 96 | return False 97 | 98 | 99 | async def speedup(bytes_io_file, fn, fe, speed): 100 | bytes_io_file.seek(0) 101 | bytes_io_file.name = fn + fe 102 | y, sr = soundfile.read(bytes_io_file) 103 | y_stretch = pyrubberband.time_stretch(y, sr, speed) 104 | y_shift = pyrubberband.pitch_shift(y, sr, speed) 105 | bytes_io_file.seek(0) 106 | soundfile.write(bytes_io_file, y_stretch, sr, format="wav") 107 | bytes_io_file.seek(0) 108 | bytes_io_file.name = fn + ".wav" 109 | return bytes_io_file, fn, fe 110 | 111 | 112 | @loader.tds 113 | class TTSMod(loader.Module): 114 | strings = { 115 | "name": "Text to speech", 116 | "tts_lang_cfg": "Set your language code for the TTS here.", 117 | "no_speed": "[TTS] Your input was an unsupported speed value.", 118 | "needspeed": "You need to provide a speed value between 0.25 and 3.0.", 119 | "no_reply": "[TTS] You need to reply to a voicemessage.", 120 | "tts_needs_text": "[TTS] I need some text to convert to speech!", 121 | "processing": "[TTS] Message is being processed ...", 122 | "needvoice": "[TTS] This command needs a voicemessage", 123 | "speech_speed": ("[TTS] Speech speed set to {}x."), 124 | } 125 | 126 | def __init__(self): 127 | self.config = loader.ModuleConfig( 128 | "TTS_LANG", "en", lambda m: self.strings("tts_lang_cfg", m) 129 | ) 130 | 131 | async def client_ready(self, client, db): 132 | self._db = db 133 | self._client = client 134 | self._me = await client.get_me(True) 135 | self.id = (await client.get_me(True)).user_id 136 | 137 | @loader.unrestricted 138 | @loader.ratelimit 139 | async def ttscmd(self, message): 140 | """Convert text to speech with Google APIs""" 141 | if self._db.get(__name__, "speech_speed") is None: 142 | speed = 1 143 | else: 144 | speed = float(self._db.get(__name__, "speech_speed")) 145 | text = utils.get_args_raw(message.message) 146 | if len(text) == 0: 147 | if message.is_reply: 148 | text = (await message.get_reply_message()).message 149 | else: 150 | await utils.answer(message, self.strings("tts_needs_text", message)) 151 | return 152 | await utils.answer(message, self.strings("processing", message)) 153 | logger.error(self.config["TTS_LANG"]) 154 | tts = await utils.run_sync(gTTS, text, lang=self.config["TTS_LANG"]) 155 | voice = BytesIO() 156 | await utils.run_sync(tts.write_to_fp, voice) 157 | voice.seek(0) 158 | voice.name = "voice.mp3" 159 | fn, fe = os.path.splitext(voice.name) 160 | voice, fn, fe = await audiohandler(voice, fn, fe) 161 | voice.seek(0) 162 | voice, fn, fe = await speedup(voice, fn, fe, float(speed)) 163 | voice.seek(0) 164 | voice, fn, fe = await audionormalizer(voice, fn, fe) 165 | voice.seek(0) 166 | voice, fn, fe = await makewaves(voice, fn, fe) 167 | voice.seek(0) 168 | voice.name = fn + fe 169 | await utils.answer(message, voice, voice_note=True) 170 | 171 | async def speedvccmd(self, message): 172 | """Speed up voice by x""" 173 | speed = utils.get_args_raw(message) 174 | if message.is_reply: 175 | replymsg = await message.get_reply_message() 176 | if not replymsg.voice: 177 | return await utils.answer(message, self.strings("needvoice", message)) 178 | else: 179 | return await utils.answer(message, self.strings("no_reply", message)) 180 | if len(speed) == 0: 181 | return await utils.answer(message, self.strings("needspeed", message)) 182 | if not represents_speed(speed): 183 | return await utils.answer(message, self.strings("no_speed", message)) 184 | await utils.answer(message, self.strings("processing", message)) 185 | ext = replymsg.file.ext 186 | voice = BytesIO() 187 | voice.name = replymsg.file.name 188 | await replymsg.client.download_file(replymsg, voice) 189 | voice.name = "voice" + ext 190 | fn, fe = os.path.splitext(voice.name) 191 | voice.seek(0) 192 | voice, fn, fe = await audiohandler(voice, fn, fe) 193 | voice.seek(0) 194 | voice, fn, fe = await speedup(voice, fn, fe, float(speed)) 195 | voice.seek(0) 196 | voice, fn, fe = await audionormalizer(voice, fn, fe) 197 | voice.seek(0) 198 | voice, fn, fe = await makewaves(voice, fn, fe) 199 | voice.seek(0) 200 | voice.name = fn + fe 201 | await utils.answer(message, voice, voice_note=True) 202 | 203 | async def ttsspeedcmd(self, message): 204 | """Set the desired speech speed 205 | - Example: .ttsspeed 1.5 (Would be 1.5x speed) 206 | Possible values between 0.25 and 3""" 207 | speed = utils.get_args_raw(message) 208 | if not represents_speed(speed): 209 | return await utils.answer(message, self.strings("no_speed", message)) 210 | self._db.set(__name__, "speech_speed", speed) 211 | await utils.answer( 212 | message, self.strings("speech_speed", message).format(str(speed)) 213 | ) 214 | -------------------------------------------------------------------------------- /imageeditor.py: -------------------------------------------------------------------------------- 1 | # Coded by D4n13l3k00 # 2 | # t.me/D4n13l3k00 # 3 | # This code under AGPL-3.0 # 4 | 5 | # requires: Pillow aiohttp fake-useragent 6 | 7 | import hashlib 8 | import io 9 | import re 10 | from datetime import date 11 | 12 | import aiohttp 13 | from fake_useragent import UserAgent 14 | from PIL import Image, ImageEnhance, ImageOps 15 | from telethon import types 16 | 17 | from .. import loader, utils 18 | 19 | 20 | @loader.tds 21 | class ImageEditorMod(loader.Module): 22 | "ImageEditor - Simple tool for working with images" 23 | strings = { 24 | "name": "ImageEditor", 25 | "downloading": "[{}] Downloading...", 26 | "working": "[{}] Working...", 27 | "exporting": "[{}] Exporting...", 28 | "set_value": "[{}] Specify the level...", 29 | "set_size": "[{}] Specify the size...", 30 | "reply": "[{}] reply to image...", 31 | "set_time": "[{}] Specify the time in the format start(ms):end(ms)", 32 | } 33 | 34 | @loader.owner 35 | async def resizeicmd(self, m: types.Message): 36 | ".resizei - Resize image" 37 | _pref = "Resize" 38 | args = utils.get_args_raw(m) 39 | r = re.compile(r"^(\d+)\s+(\d+)$") 40 | if not args or not r.match(args): 41 | return await utils.answer(m, self.strings("set_size", m).format(_pref)) 42 | w, h = [int(i) for i in r.match(args).groups()] 43 | im = await get_image(self, m, _pref) 44 | if not im: 45 | return 46 | out = im.image.resize((w, h)) 47 | await go_out(self, m, im, out, _pref) 48 | 49 | @loader.owner 50 | async def rmbgicmd(self, m: types.Message): 51 | ".rmbgi - Remove background via AI [Powered by Indian's AI]" 52 | _pref = "RemoveBg" 53 | im = await get_image(self, m, _pref) 54 | if not im: 55 | return 56 | b = io.BytesIO() 57 | b.name = "i.png" 58 | im.image.save(b, "PNG") 59 | b.seek(0) 60 | out = None 61 | async with aiohttp.ClientSession( 62 | headers={"User-Agent": UserAgent().chrome} 63 | ) as s: 64 | form = aiohttp.FormData() 65 | form.add_field("file", b) 66 | form.add_field("filenameOverride", "true") 67 | form.add_field( 68 | "path", 69 | f"__editor/{date.year}-{date.month}-{date.day}/{hashlib.md5(b.read()).hexdigest()}", 70 | ) 71 | b.seek(0) 72 | async with s.post( 73 | "https://api.erase.bg/service/panel/assets/v1.0/upload/direct", 74 | data=form, 75 | ) as r: 76 | _url = (await r.json())["url"] 77 | async with s.get( 78 | _url.replace("dummy-cloudname/original", "dummy-cloudname/erase.bg()") 79 | ) as r: 80 | i = io.BytesIO(await r.read()) 81 | i.name = "ImageEditor.jpeg" 82 | out = Image.open(i) 83 | await go_out(self, m, im, out, _pref, True) 84 | 85 | @loader.owner 86 | async def inverticmd(self, m: types.Message): 87 | ".inverti - Invert colors" 88 | _pref = "Invert" 89 | im = await get_image(self, m, _pref) 90 | if not im: 91 | return 92 | out = ImageOps.invert(im.image) 93 | await go_out(self, m, im, out, _pref) 94 | 95 | @loader.owner 96 | async def bwicmd(self, m: types.Message): 97 | ".bwi - BlackWhite" 98 | _pref = "BlackWhite" 99 | im = await get_image(self, m, _pref) 100 | if not im: 101 | return 102 | out = im.image.convert("L") 103 | await go_out(self, m, im, out, _pref) 104 | 105 | @loader.owner 106 | async def convicmd(self, m: types.Message): 107 | ".convi - Sticker to image | Image to sticker" 108 | _pref = "Converter" 109 | im = await get_image(self, m, _pref) 110 | if not im: 111 | return 112 | im.is_webp = not im.is_webp 113 | await go_out(self, m, im, im.image, _pref) 114 | 115 | @loader.owner 116 | async def rotateicmd(self, m: types.Message): 117 | ".rotatei - Rotate image" 118 | _pref = "Rotate" 119 | args = utils.get_args_raw(m) 120 | r = re.compile(r"^(\d+)$") 121 | if not args or not r.match(args): 122 | return await utils.answer(m, self.strings("set_value", m).format(_pref)) 123 | degrees = int(r.match(args).groups()[0]) 124 | im = await get_image(self, m, _pref) 125 | if not im: 126 | return 127 | out = im.image.rotate(degrees, expand=True) 128 | await go_out(self, m, im, out, _pref) 129 | 130 | @loader.owner 131 | async def contrasticmd(self, m: types.Message): 132 | ".contrasti - Change contrast" 133 | _pref = "Contrast" 134 | args = utils.get_args_raw(m) 135 | r = re.compile(r"^(\d*\.?\d*)$") 136 | if not args or not r.match(args): 137 | return await utils.answer(m, self.strings("set_value", m).format(_pref)) 138 | level = float(r.match(args).groups()[0]) 139 | im = await get_image(self, m, _pref) 140 | if not im: 141 | return 142 | out = ImageEnhance.Contrast(im.image).enhance(level) 143 | await go_out(self, m, im, out, _pref) 144 | 145 | @loader.owner 146 | async def sharpnessicmd(self, m: types.Message): 147 | ".sharpnessi - Change sharpness" 148 | _pref = "Sharpness" 149 | args = utils.get_args_raw(m) 150 | r = re.compile(r"^(\d*\.?\d*)$") 151 | if not args or not r.match(args): 152 | return await utils.answer(m, self.strings("set_value", m).format(_pref)) 153 | level = float(r.match(args).groups()[0]) 154 | im = await get_image(self, m, _pref) 155 | if not im: 156 | return 157 | out = ImageEnhance.Sharpness(im.image).enhance(level) 158 | await go_out(self, m, im, out, _pref) 159 | 160 | @loader.owner 161 | async def brighticmd(self, m: types.Message): 162 | ".brighti - Change bright" 163 | _pref = "Color" 164 | args = utils.get_args_raw(m) 165 | r = re.compile(r"^(\d*\.?\d*)$") 166 | if not args or not r.match(args): 167 | return await utils.answer(m, self.strings("set_value", m).format(_pref)) 168 | level = float(r.match(args).groups()[0]) 169 | im = await get_image(self, m, _pref) 170 | if not im: 171 | return 172 | out = ImageEnhance.Brightness(im.image).enhance(level) 173 | await go_out(self, m, im, out, _pref) 174 | 175 | @loader.owner 176 | async def coloricmd(self, m: types.Message): 177 | ".colori - Change color factor" 178 | _pref = "Color" 179 | args = utils.get_args_raw(m) 180 | r = re.compile(r"^(\d*\.?\d*)$") 181 | if not args or not r.match(args): 182 | return await utils.answer(m, self.strings("set_value", m).format(_pref)) 183 | level = float(r.match(args).groups()[0]) 184 | im = await get_image(self, m, _pref) 185 | if not im: 186 | return 187 | out = ImageEnhance.Color(im.image).enhance(level) 188 | await go_out(self, m, im, out, _pref) 189 | 190 | 191 | class ImageEditorClass: 192 | image: Image.Image = None 193 | message = None 194 | is_webp: bool = None 195 | pref: str = None 196 | reply = None 197 | 198 | 199 | async def get_image(self, m, pref: str) -> ImageEditorClass: 200 | r = await m.get_reply_message() 201 | if r and r.file and r.file.mime_type.split("/")[0] in ["image"]: 202 | im = ImageEditorClass() 203 | im.pref = pref 204 | im.reply = r 205 | im.is_webp = r.file.ext == ".webp" 206 | m = await utils.answer(m, self.strings("downloading", m).format(pref)) 207 | im.image = Image.open(io.BytesIO(await r.download_media(bytes))) 208 | im.message = await utils.answer(m, self.strings("working", m).format(pref)) 209 | return im 210 | await utils.answer(m, self.strings("reply", m).format(pref)) 211 | 212 | 213 | async def go_out( 214 | self, m, im: ImageEditorClass, out: Image.Image, pref, force_document=False 215 | ): 216 | m = await utils.answer(m, self.strings("exporting", m).format(pref)) 217 | iba = io.BytesIO() 218 | if im.is_webp: 219 | out.thumbnail((512, 512)) 220 | out.save(iba, format="WEBP" if im.is_webp else "PNG") 221 | iba.name = "ImageEditor." + ("webp" if im.is_webp else "png") 222 | iba.seek(0) 223 | await utils.answer( 224 | m, 225 | iba, 226 | reply_to=im.reply.id, 227 | supports_streaming=True, 228 | force_document=force_document if not im.is_webp else False, 229 | ) 230 | -------------------------------------------------------------------------------- /blocknondiscussion.py: -------------------------------------------------------------------------------- 1 | # Friendly Telegram (telegram userbot) module 2 | # module author: @anon97945 3 | 4 | 5 | import asyncio 6 | import logging 7 | 8 | from telethon import functions 9 | from datetime import timedelta 10 | from telethon.tl.types import User, Channel 11 | from telethon.errors import UserNotParticipantError 12 | 13 | from .. import loader, utils 14 | 15 | logger = logging.getLogger(__name__) 16 | 17 | 18 | async def is_linkedchannel(e, c, u, message): 19 | if not isinstance(e, User): 20 | full_chat = await message.client( 21 | functions.channels.GetFullChannelRequest(channel=u) 22 | ) 23 | linked_channel_id = int(str(-100) + str(full_chat.full_chat.linked_chat_id)) 24 | return c == linked_channel_id 25 | else: 26 | return False 27 | 28 | 29 | def represents_int(s): 30 | try: 31 | int(s) 32 | return True 33 | except ValueError: 34 | return False 35 | 36 | 37 | def to_bool(value): 38 | if str(value).lower() in ("true"): 39 | return True 40 | if str(value).lower() in ("false"): 41 | return False 42 | 43 | 44 | def replaced(sequence, old, new): 45 | return (new if x == old else x for x in sequence) 46 | 47 | 48 | async def is_member(c, u, message): 49 | if c != (await message.client.get_me(True)).user_id: 50 | try: 51 | await message.client.get_permissions(c, u) 52 | return True 53 | except UserNotParticipantError: 54 | return False 55 | 56 | 57 | @loader.tds 58 | class BlockNonDiscussionMod(loader.Module): 59 | """Block Comments For Non Discussion Members""" 60 | 61 | strings = { 62 | "name": "Block Non Discussion", 63 | "not_dc": "This is no Groupchat.", 64 | "start": "[BlockNonDiscussion] Activated in this chat.", 65 | "stopped": "[BlockNonDiscussion] Deactivated in this chat.", 66 | "turned_off": "[BlockNonDiscussion] The mode is turned off in all chats.", 67 | "no_int": "Your input was no int.", 68 | "error": "Your command was wrong.", 69 | "permerror": "You have no delete permissions in this chat.", 70 | "settings": ( 71 | "[BlockNonDiscussion - Settings] Current settings in this" 72 | " chat are:\n{}." 73 | ), 74 | "triggered": ( 75 | "{}, the comments are limited to discussiongroup members," 76 | "please join our discussiongroup first." 77 | "\n\n👉🏻 {}" 78 | "\n\nRespectfully, the admins." 79 | ), 80 | } 81 | 82 | def __init__(self): 83 | self._ratelimit = [] 84 | 85 | async def client_ready(self, client, db): 86 | self._db = db 87 | self._client = client 88 | self._me = await client.get_me(True) 89 | 90 | async def bndcmd(self, message): 91 | """Available commands: 92 | .bnd 93 | - Toggles the module for the current chat. 94 | .bnd notify 95 | - Toggles the notification message. 96 | .bnd mute 97 | - Mutes the user for x minutes. 0 to disable. 98 | .bnd deltimer 99 | - Deletes the notification message in seconds. 0 to disable. 100 | .bnd clearall 101 | - Clears the db of the module""" 102 | bnd = self._db.get(__name__, "bnd", []) 103 | sets = self._db.get(__name__, "sets", {}) 104 | args = utils.get_args_raw(message).lower() 105 | args = str(args).split() 106 | chat = await message.get_chat() 107 | chatid = message.chat_id 108 | chatid_str = str(chatid) 109 | 110 | if args: 111 | if args[0] == "clearall": 112 | self._db.set(__name__, "bnd", []) 113 | self._db.set(__name__, "sets", {}) 114 | return await utils.answer(message, self.strings("turned_off", message)) 115 | 116 | if message.is_private: 117 | await utils.answer(message, self.strings("not_dc", message)) 118 | return 119 | 120 | if not chat.admin_rights and not chat.creator: 121 | return await utils.answer(message, self.strings("permerror", message)) 122 | else: 123 | if not chat.admin_rights.delete_messages: 124 | return await utils.answer(message, self.strings("permerror", message)) 125 | 126 | if not args: 127 | if chatid_str not in bnd: 128 | bnd.append(chatid_str) 129 | sets.setdefault(chatid_str, {}) 130 | sets[chatid_str].setdefault("notify", True) 131 | sets[chatid_str].setdefault("mute", 1) 132 | sets[chatid_str].setdefault("deltimer", 60) 133 | self._db.set(__name__, "bnd", bnd) 134 | self._db.set(__name__, "sets", sets) 135 | return await utils.answer(message, self.strings("start", message)) 136 | else: 137 | bnd.remove(chatid_str) 138 | sets.pop(chatid_str) 139 | self._db.set(__name__, "bnd", bnd) 140 | self._db.set(__name__, "sets", sets) 141 | return await utils.answer(message, self.strings("stopped", message)) 142 | 143 | if chatid_str in bnd: 144 | if args[0] == "notify" and args[1] is not None and chatid_str in bnd: 145 | if not isinstance(to_bool(args[1]), bool): 146 | return await utils.answer(message, self.strings("error", message)) 147 | sets[chatid_str].update({"notify": to_bool(args[1])}) 148 | elif args[0] == "mute" and args[1] is not None and chatid_str in bnd: 149 | if not represents_int(args[1]): 150 | return await utils.answer(message, self.strings("no_int", message)) 151 | else: 152 | sets[chatid_str].update({"mute": args[1].capitalize()}) 153 | elif args[0] == "deltimer" and args[1] is not None and chatid_str in bnd: 154 | if not represents_int(args[1]): 155 | return await utils.answer(message, self.strings("no_int", message)) 156 | else: 157 | sets[chatid_str].update({"deltimer": args[1]}) 158 | elif args[0] != "settings" and chatid_str in bnd: 159 | return 160 | self._db.set(__name__, "sets", sets) 161 | return await utils.answer( 162 | message, self.strings("settings", message).format(str(sets[chatid_str])) 163 | ) 164 | 165 | async def watcher(self, message): 166 | if not getattr(message, "raw_text", False): 167 | return 168 | 169 | bnd = self._db.get(__name__, "bnd", []) 170 | sets = self._db.get(__name__, "sets", {}) 171 | chatid = message.chat_id 172 | chatid_str = str(chatid) 173 | if message.is_private or chatid_str not in bnd: 174 | return 175 | chat = await message.get_chat() 176 | user = await message.get_sender() 177 | userid = message.sender_id 178 | entity = await message.client.get_entity(message.sender_id) 179 | 180 | if (await is_linkedchannel(entity, chatid, userid, message)) or isinstance( 181 | entity, Channel 182 | ): 183 | return 184 | 185 | if ( 186 | (chat.admin_rights or chat.creator) 187 | and not chat.admin_rights.delete_messages 188 | or not chat.admin_rights 189 | and not chat.creator 190 | ): 191 | return 192 | 193 | usertag = ( 194 | "" 197 | + user.first_name 198 | + " (" 199 | + str(userid) 200 | + ")" 201 | ) 202 | if (await message.client.get_entity(chatid)).username: 203 | link = "https://t.me/" + str( 204 | (await message.client.get_entity(chatid)).username 205 | ) 206 | elif chat.admin_rights.invite_users: 207 | link = await message.client( 208 | functions.channels.GetFullChannelRequest(channel=chatid) 209 | ) 210 | link = link.full_chat.exported_invite.link 211 | else: 212 | link = "" 213 | if not (await is_member(chatid, userid, message)): 214 | await message.delete() 215 | if ( 216 | chat.admin_rights.ban_users 217 | and sets[chatid_str].get("mute") is not None 218 | and sets[chatid_str].get("mute") != "0" 219 | ): 220 | MUTETIMER = sets[chatid_str].get("mute") 221 | await message.client.edit_permissions( 222 | chatid, 223 | userid, 224 | timedelta(minutes=MUTETIMER), 225 | send_messages=False, 226 | ) 227 | if sets[chatid_str].get("notify") is True: 228 | msgs = await utils.answer( 229 | message, self.strings("triggered", message).format(usertag, link) 230 | ) 231 | if sets[chatid_str].get("deltimer") != "0": 232 | DELTIMER = int(sets[chatid_str].get("deltimer")) 233 | await asyncio.sleep(DELTIMER) 234 | await message.client.delete_messages(chatid, msgs) 235 | -------------------------------------------------------------------------------- /SeeChat.py: -------------------------------------------------------------------------------- 1 | from .. import loader, utils 2 | from datetime import datetime, date, time 3 | from asyncio import sleep 4 | import os, io, asyncio, pytz, requests 5 | 6 | 7 | @loader.tds 8 | class SeeChatMod(loader.Module): 9 | """tracking in all PM chats.""" 10 | 11 | strings = {"name": "SeeChat"} 12 | 13 | async def client_ready(self, message, db): 14 | self.db = db 15 | self.db.set("SeeChat", "seechat", True) 16 | di = "SeeChat/" 17 | if os.path.exists(di): 18 | None 19 | else: 20 | os.mkdir(di) 21 | 22 | async def seechatcmd(self, message): 23 | """use: .seechat | to enable tracking in all PM chats.""" 24 | 25 | if not await message.client.get_me(): 26 | return await message.edit("Something went wrong..") 27 | if self.db.get("SeeChat", "seechat") is not True: 28 | await message.edit("[SeeChat] turned on seccsessfully.") 29 | self.db.set("SeeChat", "seechat", True) 30 | else: 31 | await message.edit("[SeeChat] turned off seccsessfully.") 32 | self.db.set("SeeChat", "seechat", False) 33 | 34 | async def setchatcmd(self, message): 35 | """use: .setchat | to set this chat as a track chat.""" 36 | 37 | if not await message.client.get_me(): 38 | return await message.edit("Something went wrong..") 39 | chat = await message.client.get_entity(message.to_id) 40 | self.db.set("SeeChat", "log", str(chat.id)) 41 | await message.edit("This chat was set as a chat for tracks.") 42 | 43 | async def seechatscmd(self, message): 44 | """use: .seechats | to see the list of tracking people.""" 45 | 46 | if not message.client.get_me(): 47 | return await message.edit("Something went wrong..") 48 | await message.edit("wait a second..") 49 | chats = "" 50 | number = 0 51 | for _ in os.listdir("SeeChat/"): 52 | number += 1 53 | try: 54 | user = await message.client.get_entity(int(_[:-4])) 55 | except: 56 | pass 57 | if not user.deleted: 58 | chats += f"{number} • {user.first_name} ID: [{user.id}]\n" 59 | else: 60 | chats += f"{number} • Deleted account ID: [{user.id}]\n" 61 | await message.edit("tracking users:\n\n" + chats) 62 | 63 | async def gseecmd(self, message): 64 | """use: .gsee {id} | to get the tracked file.""" 65 | 66 | if not message.client.get_me(): 67 | return await message.edit("Something went wrong..") 68 | args = utils.get_args_raw(message) 69 | if not args: 70 | return await message.edit("what about args?") 71 | try: 72 | user = await message.client.get_entity(int(args)) 73 | await message.edit(f"PM file with: {user.first_name}") 74 | await message.client.send_file(message.to_id, f"SeeChat/{args}.txt") 75 | except: 76 | return await message.edit("file is empty.") 77 | 78 | async def delseecmd(self, message): 79 | """use: .delsee {id} | to delete the tracked file.""" 80 | 81 | if not message.client.get_me(): 82 | return await message.edit("Something went wrong..") 83 | args = utils.get_args_raw(message) 84 | if not args: 85 | return await message.edit("what about args?") 86 | if args == "all": 87 | os.system("rm -rf SeeChat/*") 88 | await message.edit( 89 | "all PM chats file has been successfully deleted." 90 | ) 91 | else: 92 | try: 93 | user = await message.client.get_entity(int(args)) 94 | await message.edit( 95 | f"the chat file has been deleted with: {user.first_name}" 96 | ) 97 | os.remove(f"SeeChat/{args}.txt") 98 | except: 99 | return await message.edit("file can't be deleted.") 100 | 101 | async def excseecmd(self, message): 102 | """use: .excsee {id} | to add / remove user from exclude tracking.""" 103 | 104 | if not message.client.get_me(): 105 | return await message.edit("Something went wrong..") 106 | exception = self.db.get("SeeChat", "exception", []) 107 | args = utils.get_args_raw(message) 108 | if not args: 109 | return await message.edit("what about args?") 110 | if args == "clear": 111 | self.db.set("SeeChat", "exception", []) 112 | return await message.edit( 113 | "the exclusion list was cleared successfully." 114 | ) 115 | try: 116 | user = await message.client.get_entity(int(args)) 117 | if str(user.id) not in exception: 118 | exception.append(str(user.id)) 119 | await message.edit( 120 | f"{user.first_name}, has been added to the list of exclusions." 121 | ) 122 | os.remove(f"SeeChat/{user.id}.txt") 123 | else: 124 | exception.remove(str(user.id)) 125 | await message.edit( 126 | f"{user.first_name}, has been removed from the list of exclusions." 127 | ) 128 | self.db.set("SeeChat", "exception", exception) 129 | except: 130 | return await message.edit( 131 | "failed to remove user from the list of exclusions" 132 | ) 133 | 134 | async def exclistcmd(self, message): 135 | """use: .exclist | to see the list of exceptions.""" 136 | 137 | if not message.client.get_me(): 138 | return await message.edit("Something went wrong..") 139 | exception = self.db.get("SeeChat", "exception", []) 140 | number = 0 141 | users = "" 142 | try: 143 | for _ in exception: 144 | user = await message.client.get_entity(int(_)) 145 | number += 1 146 | users += f"{number} • {user.first_name} ID: [{user.id}]\n" 147 | await message.edit("list of exclusions:\n\n" + users) 148 | except: 149 | return await message.edit("the list of users is empty.") 150 | 151 | async def watcher(self, message): 152 | me = await message.client.get_me() 153 | seechat = self.db.get("SeeChat", "seechat") 154 | exception = self.db.get("SeeChat", "exception", []) 155 | log = self.db.get("SeeChat", "log", str(me.id)) 156 | chat = await message.client.get_entity(int(log)) 157 | timezone = "Europe/Kiev" 158 | vremya = datetime.now(pytz.timezone(timezone)).strftime("[%Y-%m-%d %H:%M:%S]") 159 | user = await message.client.get_entity(message.chat_id) 160 | userid = str(user.id) 161 | try: 162 | if message.sender_id == me.id: 163 | user.first_name = me.first_name 164 | except: 165 | pass 166 | if ( 167 | message.is_private 168 | and seechat is not False 169 | and userid not in exception 170 | and not user.bot 171 | and not user.verified 172 | ): 173 | if message.text.lower(): 174 | file = open(f"SeeChat/{user.id}.txt", "a", encoding="utf-8") 175 | file.write(f"{user.first_name} >> {message.text} << {vremya}\n\n") 176 | if message.photo: 177 | if message.sender_id == me.id: 178 | return 179 | file = io.BytesIO() 180 | file.name = message.file.name or f"SeeChat{message.file.ext}" 181 | await message.client.download_file(message, file) 182 | file.seek(0) 183 | await message.client.send_message( 184 | chat.id, 185 | f"picture from {user.first_name}:", 186 | ) 187 | await message.client.send_file(chat.id, file, force_document=False) 188 | if ( 189 | not message.voice 190 | and not message.video_note 191 | and not message.video 192 | and message.audio 193 | and message.sender_id == me.id 194 | or not message.voice 195 | and not message.video_note 196 | and not message.video 197 | and not message.audio 198 | and message.document 199 | and message.sender_id == me.id 200 | ): 201 | return 202 | elif ( 203 | not message.voice 204 | and not message.video_note 205 | and not message.video 206 | and message.audio 207 | or not message.voice 208 | and not message.video_note 209 | and not message.video 210 | and message.document 211 | or not message.voice 212 | and not message.video_note 213 | and not message.video 214 | ): 215 | pass 216 | elif message.voice or message.video_note: 217 | if message.sender_id == me.id: 218 | return 219 | await message.forward_to(chat.id) 220 | else: 221 | if message.sender_id == me.id: 222 | return 223 | try: 224 | file = message.file.name or "huita" + message.file.ext 225 | await message.download_media(file) 226 | await message.client.send_message( 227 | chat.id, 228 | f"Video from {user.first_name}:", 229 | ) 230 | await message.client.send_file(chat.id, file) 231 | os.remove(file) 232 | except: 233 | pass 234 | -------------------------------------------------------------------------------- /autoprofile.py: -------------------------------------------------------------------------------- 1 | # Friendly Telegram (telegram userbot) 2 | # Copyright (C) 2018-2019 The Authors 3 | 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU Affero General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU Affero General Public License for more details. 13 | 14 | # You should have received a copy of the GNU Affero General Public License 15 | # along with this program. If not, see . 16 | 17 | import asyncio 18 | import ast 19 | import time 20 | import logging 21 | from io import BytesIO 22 | from telethon.tl import functions 23 | from .. import loader, utils 24 | 25 | logger = logging.getLogger(__name__) 26 | 27 | try: 28 | from PIL import Image 29 | except ImportError: 30 | pil_installed = False 31 | else: 32 | pil_installed = True 33 | 34 | 35 | @loader.tds 36 | class AutoProfileMod(loader.Module): 37 | """Automatic stuff for your profile :P""" 38 | 39 | strings = { 40 | "name": "Automatic Profile", 41 | "missing_pil": "You don't have Pillow installed", 42 | "missing_pfp": "You don't have a profile picture to rotate", 43 | "invalid_args": "Missing parameters, please read the docs", 44 | "invalid_degrees": "Invalid number of degrees to rotate, please read the docs", 45 | "invalid_delete": "Please specify whether to delete the old pictures or not", 46 | "enabled_pfp": "Enabled profile picture rotation", 47 | "pfp_not_enabled": "Profile picture rotation is not enabled", 48 | "pfp_disabled": "Profile picture rotation disabled", 49 | "missing_time": "Time was not specified in bio", 50 | "enabled_bio": "Enabled bio clock", 51 | "bio_not_enabled": "Bio clock is not enabled", 52 | "disabled_bio": "Disabled bio clock", 53 | "enabled_name": "Enabled name clock", 54 | "name_not_enabled": "Name clock is not enabled", 55 | "disabled_name": "Name clock disabled", 56 | "how_many_pfps": "Please specify how many profile pictures should be removed", 57 | "invalid_pfp_count": "Invalid number of profile pictures to remove", 58 | "removed_pfps": "Removed {} profile pic(s)", 59 | } 60 | 61 | def __init__(self): 62 | self.bio_enabled = False 63 | self.name_enabled = False 64 | self.pfp_enabled = False 65 | self.raw_bio = None 66 | self.raw_name = None 67 | 68 | async def client_ready(self, client, db): 69 | self.client = client 70 | 71 | async def autopfpcmd(self, message): 72 | """Rotates your profile picture every 60 seconds with x degrees, usage: 73 | .autopfp 74 | 75 | Degrees - 60, -10, etc 76 | Remove last pfp - True/1/False/0, case sensitive""" 77 | 78 | if not pil_installed: 79 | return await utils.answer(message, self.strings("missing_pil", message)) 80 | 81 | if not await self.client.get_profile_photos("me", limit=1): 82 | return await utils.answer(message, self.strings("missing_pfp", message)) 83 | 84 | msg = utils.get_args(message) 85 | if len(msg) != 2: 86 | return await utils.answer(message, self.strings("invalid_args", message)) 87 | 88 | try: 89 | degrees = int(msg[0]) 90 | except ValueError: 91 | return await utils.answer(message, self.strings("invalid_degrees", message)) 92 | 93 | try: 94 | delete_previous = ast.literal_eval(msg[1]) 95 | except (ValueError, SyntaxError): 96 | return await utils.answer(message, self.strings("invalid_delete", message)) 97 | 98 | with BytesIO() as pfp: 99 | await self.client.download_profile_photo("me", file=pfp) 100 | raw_pfp = Image.open(pfp) 101 | 102 | self.pfp_enabled = True 103 | pfp_degree = 0 104 | await self.allmodules.log("start_autopfp") 105 | await utils.answer(message, self.strings("enabled_pfp", message)) 106 | 107 | while self.pfp_enabled: 108 | pfp_degree = (pfp_degree + degrees) % 360 109 | rotated = raw_pfp.rotate(pfp_degree) 110 | with BytesIO() as buf: 111 | rotated.save(buf, format="JPEG") 112 | buf.seek(0) 113 | 114 | if delete_previous: 115 | await self.client( 116 | functions.photos.DeletePhotosRequest( 117 | await self.client.get_profile_photos("me", limit=1) 118 | ) 119 | ) 120 | 121 | await self.client( 122 | functions.photos.UploadProfilePhotoRequest( 123 | await self.client.upload_file(buf) 124 | ) 125 | ) 126 | buf.close() 127 | await asyncio.sleep(60) 128 | 129 | async def stopautopfpcmd(self, message): 130 | """Stop autobio cmd.""" 131 | 132 | if self.pfp_enabled is False: 133 | return await utils.answer(message, self.strings("pfp_not_enabled", message)) 134 | self.pfp_enabled = False 135 | 136 | await self.client( 137 | functions.photos.DeletePhotosRequest( 138 | await self.client.get_profile_photos("me", limit=1) 139 | ) 140 | ) 141 | await self.allmodules.log("stop_autopfp") 142 | await utils.answer(message, self.strings("pfp_disabled", message)) 143 | 144 | async def autobiocmd(self, message): 145 | """Automatically changes your account's bio with current time, usage: 146 | .autobio ''""" 147 | 148 | msg = utils.get_args(message) 149 | if len(msg) != 1: 150 | return await utils.answer(message, self.strings("invalid_args", message)) 151 | raw_bio = msg[0] 152 | if "{time}" not in raw_bio: 153 | return await utils.answer(message, self.strings("missing_time", message)) 154 | 155 | self.bio_enabled = True 156 | self.raw_bio = raw_bio 157 | await self.allmodules.log("start_autobio") 158 | await utils.answer(message, self.strings("enabled_bio", message)) 159 | 160 | while self.bio_enabled: 161 | current_time = time.strftime("%H:%M") 162 | bio = raw_bio.format(time=current_time) 163 | await self.client(functions.account.UpdateProfileRequest(about=bio)) 164 | await asyncio.sleep(60) 165 | 166 | async def stopautobiocmd(self, message): 167 | """Stop autobio cmd.""" 168 | 169 | if self.bio_enabled is False: 170 | return await utils.answer(message, self.strings("bio_not_enabled", message)) 171 | self.bio_enabled = False 172 | await self.allmodules.log("stop_autobio") 173 | await utils.answer(message, self.strings("disabled_bio", message)) 174 | await self.client( 175 | functions.account.UpdateProfileRequest(about=self.raw_bio.format(time="")) 176 | ) 177 | 178 | async def autonamecmd(self, message): 179 | """Automatically changes your Telegram name with current time, usage: 180 | .autoname ''""" 181 | 182 | msg = utils.get_args(message) 183 | if len(msg) != 1: 184 | return await utils.answer(message, self.strings("invalid_args", message)) 185 | raw_name = msg[0] 186 | if "{time}" not in raw_name: 187 | return await utils.answer(message, self.strings("missing_time", message)) 188 | 189 | self.name_enabled = True 190 | self.raw_name = raw_name 191 | await self.allmodules.log("start_autoname") 192 | await utils.answer(message, self.strings("enabled_name", message)) 193 | 194 | while self.name_enabled: 195 | current_time = time.strftime("%H:%M") 196 | name = raw_name.format(time=current_time) 197 | await self.client(functions.account.UpdateProfileRequest(first_name=name)) 198 | await asyncio.sleep(60) 199 | 200 | async def stopautonamecmd(self, message): 201 | """Stop autoname cmd.""" 202 | 203 | if self.name_enabled is False: 204 | return await utils.answer( 205 | message, self.strings("name_not_enabled", message) 206 | ) 207 | self.name_enabled = False 208 | await self.allmodules.log("stop_autoname") 209 | await utils.answer(message, self.strings("disabled_name", message)) 210 | await self.client( 211 | functions.account.UpdateProfileRequest( 212 | first_name=self.raw_name.format(time="") 213 | ) 214 | ) 215 | 216 | async def delpfpcmd(self, message): 217 | """Remove x profile pic(s) from your profile. 218 | .delpfp """ 219 | 220 | args = utils.get_args(message) 221 | if not args: 222 | return await utils.answer(message, self.strings("how_many_pfps", message)) 223 | try: 224 | pfps_count = int(args[0]) 225 | except ValueError: 226 | return await utils.answer( 227 | message, self.strings("invalid_pfp_count", message) 228 | ) 229 | if pfps_count < 0: 230 | return await utils.answer( 231 | message, self.strings("invalid_pfp_count", message) 232 | ) 233 | if pfps_count == 0: 234 | pfps_count = None 235 | 236 | to_delete = await self.client.get_profile_photos("me", limit=pfps_count) 237 | await self.client(functions.photos.DeletePhotosRequest(to_delete)) 238 | 239 | await self.allmodules.log("delpfp") 240 | await utils.answer( 241 | message, self.strings("removed_pfps", message).format(len(to_delete)) 242 | ) 243 | return await utils.answer(message, self.strings("how_many_pfps", message)) 244 | -------------------------------------------------------------------------------- /video_editor.py: -------------------------------------------------------------------------------- 1 | # Coded by D4n1l3k300 # 2 | # t.me/D4n13l3k00 # 3 | # This code under AGPL-3.0 # 4 | 5 | # requires: moviepy requests 6 | 7 | import os 8 | import random as rnd 9 | import re 10 | import string 11 | 12 | import requests 13 | from moviepy.editor import * 14 | from telethon import types 15 | 16 | from .. import loader, utils 17 | 18 | 19 | @loader.tds 20 | class VideoEditorMod(loader.Module): 21 | "Module for working with video" 22 | 23 | strings = { 24 | "name": "VideoEditor", 25 | "downloading": "[{}] Downloading...", 26 | "working": "[{}] Working...", 27 | "exporting": "[{}] Exporting...", 28 | "set_value": "[{}] Specify the level from {} to {}...", 29 | "reply": "[{}] reply to video/gif...", 30 | "set_time": "[{}] Specify the time in the format start(ms):end(ms)", 31 | "set_link": "[{}] Enter link...", 32 | } 33 | 34 | @loader.owner 35 | async def xflipvcmd(self, m: types.Message): 36 | """.xflipv - Flip video by X""" 37 | vid = await get_video(self, m, "XFlip") 38 | if not vid: 39 | return 40 | out = vid.video.fx(vfx.mirror_x) 41 | await go_out(self, vid.message, vid, out, vid.pref) 42 | 43 | @loader.owner 44 | async def yflipvcmd(self, m: types.Message): 45 | """.yflipv - Flip video by Y""" 46 | vid = await get_video(self, m, "YFlip") 47 | if not vid: 48 | return 49 | out = vid.video.fx(vfx.mirror_y) 50 | await go_out(self, vid.message, vid, out, vid.pref) 51 | 52 | @loader.owner 53 | async def bwvcmd(self, m: types.Message): 54 | """.bwv - BlackWhite""" 55 | vid = await get_video(self, m, "BlackWhite") 56 | if not vid: 57 | return 58 | out = vid.video.fx(vfx.blackwhite) 59 | await go_out(self, vid.message, vid, out, vid.pref) 60 | 61 | @loader.owner 62 | async def revvcmd(self, m: types.Message): 63 | """.revv - Reverse video""" 64 | vid = await get_video(self, m, "Reverse") 65 | if not vid: 66 | return 67 | out = vid.video.fx(vfx.time_mirror) 68 | await go_out(self, vid.message, vid, out, vid.pref) 69 | 70 | @loader.owner 71 | async def paintvcmd(self, m: types.Message): 72 | """.paintv - Paint effect""" 73 | vid = await get_video(self, m, "Paint") 74 | if not vid: 75 | return 76 | out = vid.video.fx(vfx.painting) 77 | await go_out(self, vid.message, vid, out, vid.pref) 78 | 79 | @loader.owner 80 | async def invertvcmd(self, m: types.Message): 81 | """.invertv - Invert colors""" 82 | vid = await get_video(self, m, "Invert") 83 | if not vid: 84 | return 85 | out = vid.video.fx(vfx.invert_colors) 86 | await go_out(self, vid.message, vid, out, vid.pref) 87 | 88 | @loader.owner 89 | async def rmsvcmd(self, m: types.Message): 90 | """.rmsv - Remove sound (to gif without compression)""" 91 | vid = await get_video(self, m, "NoAudio") 92 | if not vid: 93 | return 94 | out = vid.video.without_audio() 95 | await go_out(self, vid.message, vid, out, vid.pref) 96 | 97 | @loader.owner 98 | async def cutvcmd(self, m: types.Message): 99 | """.cutv - Cut video""" 100 | args = utils.get_args_raw(m) 101 | if not args: 102 | return await utils.answer(m, self.strings("set_time", m).format("Cut")) 103 | r = re.compile(r"^(?P\d+){0,1}:(?P-?\d+){0,1}$") 104 | ee = r.match(args) 105 | if not ee: 106 | return await utils.answer(m, self.strings("set_time", m).format("Cut")) 107 | start = int(ee.group("start")) if ee.group("start") else 0 108 | end = int(ee.group("end")) if ee.group("end") else None 109 | vid = await get_video(self, m, "Cut") 110 | if not vid: 111 | return 112 | out = vid.video.subclip(start, end) 113 | await go_out(self, vid.message, vid, out, vid.pref) 114 | 115 | @loader.owner 116 | async def audvcmd(self, m: types.Message): 117 | """.audv - Add audio to video""" 118 | args = utils.get_args_raw(m) 119 | if not args: 120 | return await utils.answer(m, self.strings("set_link", m).format("Audio")) 121 | r = re.compile( 122 | r"((http|https)\:\/\/)?[a-zA-Z0-9\.\/\?\:@\-_=#]+\.([a-zA-Z]){2,6}([a-zA-Z0-9\.\&\/\?\:@\-_=#])*" 123 | ) 124 | ee = r.match(args) 125 | if not ee: 126 | return await utils.answer(m, self.strings("set_link", m).format("Audio")) 127 | vid = await get_video(self, m, "Audio") 128 | if not vid: 129 | return 130 | a = requests.get(args) 131 | nm = "".join(rnd.sample(string.ascii_letters, 24)) + ".mp3" 132 | if a.status_code == 200: 133 | open(nm, "wb").write(a.content) 134 | else: 135 | return 136 | out = vid.video 137 | out.audio = CompositeAudioClip([AudioFileClip(nm)]) 138 | await go_out(self, vid.message, vid, out, vid.pref) 139 | try: 140 | os.remove(nm) 141 | except: 142 | pass 143 | 144 | @loader.owner 145 | async def fpsvcmd(self, m: types.Message): 146 | """.fpsv - Change fps""" 147 | args = utils.get_args_raw(m) 148 | if not args: 149 | fps = 30 150 | elif re.match(r"^\d+$", args) and (0 < int(args) < 241): 151 | fps = int(args) 152 | else: 153 | return await utils.answer( 154 | m, self.strings("set_value", m).format("FPS", 1, 240) 155 | ) 156 | vid = await get_video(self, m, "FPS") 157 | if not vid: 158 | return 159 | out = vid.video.set_fps(fps) 160 | await go_out(self, vid.message, vid, out, vid.pref) 161 | 162 | @loader.owner 163 | async def marginvcmd(self, m: types.Message): 164 | """.marginv - Add marging""" 165 | args = utils.get_args_raw(m) 166 | if not args: 167 | margin = 5 168 | elif re.match(r"^\d+$", args) and (0 < int(args) < 101): 169 | margin = int(args) 170 | else: 171 | return await utils.answer( 172 | m, self.strings("set_value", m).format("Scale", 1, 100) 173 | ) 174 | vid = await get_video(self, m, "Margin") 175 | if not vid: 176 | return 177 | out = vid.video.fx(vfx.margin, margin) 178 | await go_out(self, vid.message, vid, out, vid.pref) 179 | 180 | @loader.owner 181 | async def speedvcmd(self, m: types.Message): 182 | """.speedv - Speed""" 183 | args = utils.get_args_raw(m) 184 | if not args: 185 | speed = 1.5 186 | elif re.match(r"^\d+(\.\d+)?$", args) and (0.009 < float(args) < 10.1): 187 | speed = float(args) 188 | else: 189 | return await utils.answer( 190 | m, self.strings("set_value", m).format("Speed", 0.01, 10.0) 191 | ) 192 | vid = await get_video(self, m, "Speed") 193 | if not vid: 194 | return 195 | out = vid.video.fx(vfx.speedx, speed) 196 | await go_out(self, vid.message, vid, out, vid.pref) 197 | 198 | @loader.owner 199 | async def contrastvcmd(self, m: types.Message): 200 | """.contrastv - Contrast""" 201 | args = utils.get_args_raw(m) 202 | if not args: 203 | contrast = 1.5 204 | elif re.match(r"^\d+(\.\d+)?$", args) and (0.009 < float(args) < 100.1): 205 | contrast = float(args) 206 | else: 207 | return await utils.answer( 208 | m, self.strings("set_value", m).format("Contrast", 0.01, 100.0) 209 | ) 210 | vid = await get_video(self, m, "Contrast") 211 | if not vid: 212 | return 213 | out = vid.video.fx(vfx.lum_contrast, contrast=contrast) 214 | await go_out(self, vid.message, vid, out, vid.pref) 215 | 216 | @loader.owner 217 | async def lumvcmd(self, m: types.Message): 218 | """.lumv - Lum""" 219 | args = utils.get_args_raw(m) 220 | if not args: 221 | lum = 25 222 | elif re.match(r"^\d+(\.\d+)?$", args) and (0.009 < float(args) < 100.1): 223 | lum = float(args) 224 | else: 225 | return await utils.answer( 226 | m, self.strings("set_value", m).format("Lum", 0.01, 100.0) 227 | ) 228 | vid = await get_video(self, m, "Lum") 229 | if not vid: 230 | return 231 | out = vid.video.fx(vfx.lum_contrast, lum=lum) 232 | await go_out(self, vid.message, vid, out, vid.pref) 233 | 234 | @loader.owner 235 | async def scalevcmd(self, m: types.Message): 236 | """.scalev - Scale("Resize") video""" 237 | args = utils.get_args_raw(m) 238 | if not args: 239 | scale = 0.75 240 | elif re.match(r"^\d+(\.\d+)?$", args) and (0.009 < float(args) < 100.1): 241 | scale = float(args) 242 | else: 243 | return await utils.answer( 244 | m, self.strings("set_value", m).format("Scale", 0.01, 100.0) 245 | ) 246 | vid = await get_video(self, m, "Scale") 247 | if not vid: 248 | return 249 | out = vid.video.resize(scale) 250 | await go_out(self, vid.message, vid, out, vid.pref) 251 | 252 | 253 | class VideoEditorClass: 254 | video: VideoFileClip = None 255 | message = None 256 | pref: str = None 257 | reply = None 258 | 259 | 260 | async def get_video(self, m, pref: str): 261 | r = await m.get_reply_message() 262 | if r and r.file and r.file.mime_type.split("/")[0] in ["video"]: 263 | vid = VideoEditorClass() 264 | vid.pref = pref 265 | vid.reply = r 266 | vid.message = await utils.answer(m, self.strings("downloading", m).format(pref)) 267 | vid.video = VideoFileClip(await r.download_media()) 268 | return vid 269 | await utils.answer(m, self.strings("reply", m).format(pref)) 270 | 271 | 272 | async def go_out(self, m, vid: VideoEditorClass, out: VideoFileClip, pref): 273 | m = await utils.answer(m, self.strings("exporting", m).format(pref)) 274 | filename = "".join(rnd.sample(string.ascii_letters, 24)) + ".mp4" 275 | out.write_videofile(filename) 276 | await utils.answer( 277 | m, open(filename, "rb"), reply_to=vid.reply.id, supports_streaming=True 278 | ) 279 | try: 280 | os.remove(filename) 281 | except: 282 | pass 283 | try: 284 | os.remove(vid.video.filename) 285 | except: 286 | pass 287 | -------------------------------------------------------------------------------- /voicemod.py: -------------------------------------------------------------------------------- 1 | # Coded by D4n1l3k300 # 2 | # supplemented by Yahikor0 # 3 | # This code under AGPL-3.0 # 4 | 5 | # requires: ffmpeg-python pytgcalls[telethon] youtube-dl ShazamAPI 6 | 7 | import io 8 | import os 9 | import re 10 | import logging 11 | 12 | import ffmpeg 13 | import pytgcalls 14 | from ShazamAPI import Shazam 15 | from youtube_dl import YoutubeDL 16 | from pytgcalls import GroupCallFactory 17 | from pytgcalls.implementation.group_call_file import GroupCallFile 18 | from telethon import types 19 | from typing import * 20 | 21 | from .. import loader, utils 22 | 23 | 24 | @loader.unrestricted 25 | @loader.ratelimit 26 | @loader.tds 27 | class VoiceMod(loader.Module): 28 | """Module for working with voicechat""" 29 | 30 | strings = { 31 | "name": "VoiceMod", 32 | "downloading": "[VoiceMod] Downloading...", 33 | "converting": "[VoiceMod] Converting...", 34 | "playing": "[VoiceMod] Playing...", 35 | "plsjoin": "[VoiceMod] You are not joined (type .vjoin)", 36 | "stop": "[VoiceMod] Playing stopped!", 37 | "join": "[VoiceMod] Joined!", 38 | "leave": "[VoiceMod] Leaved!", 39 | "pause": "[VoiceMod] Paused!", 40 | "resume": "[VoiceMod] Resumed!", 41 | "mute": "[VoiceMod] Muted!", 42 | "unmute": "[VoiceMod] Unmuted!", 43 | "replay": "[VoiceMod] Replaying...", 44 | "error": "[VoiceMod] Error: {}", 45 | } 46 | ytdlopts = { 47 | "format": "bestaudio", 48 | "addmetadata": True, 49 | "key": "FFmpegMetadata", 50 | "writethumbnail": True, 51 | "prefer_ffmpeg": True, 52 | "geo_bypass": True, 53 | "nocheckcertificate": True, 54 | "postprocessors": [ 55 | { 56 | "key": "FFmpegExtractAudio", 57 | "preferredcodec": "mp3", 58 | "preferredquality": "320", 59 | } 60 | ], 61 | "outtmpl": "ytdl_out.mp3", 62 | "quiet": True, 63 | "logtostderr": False, 64 | } 65 | group_calls: Dict[int, GroupCallFile] = {} 66 | 67 | tag = "[Shazam] " 68 | 69 | async def get_chat(self, m: types.Message): 70 | args = utils.get_args_raw(m) 71 | if not args: 72 | chat = m.chat.id 73 | else: 74 | try: 75 | chat = int(args) 76 | except: 77 | chat = args 78 | try: 79 | chat = (await m.client.get_entity(chat)).id 80 | except Exception as e: 81 | await utils.answer(m, self.strings("error").format(str(e))) 82 | return None 83 | return chat 84 | 85 | def _call(self, m: types.Message, chat: int): 86 | if str(chat) not in self.group_calls: 87 | self.group_calls[str(chat)] = GroupCallFactory( 88 | m.client, pytgcalls.GroupCallFactory.MTPROTO_CLIENT_TYPE.TELETHON 89 | ).get_file_group_call() 90 | 91 | async def client_ready(self, client, db): 92 | self.client = client 93 | self.db = db 94 | 95 | async def vplaycmd(self, m: types.Message): 96 | """.vplay [chat (optional)] 97 | Play audio in VC""" 98 | args = utils.get_args_raw(m) 99 | r = await m.get_reply_message() 100 | chat = from_file = link = None 101 | if args: 102 | _ = re.match(r"(-?\d+|@[A-Za-z0-9_]{5,})\s+(.*)", args) 103 | __ = re.match(r"(-?\d+|@[A-Za-z0-9_]{5,})", args) 104 | if _: 105 | chat = _.group(1) 106 | link = _.group(2) 107 | elif __: 108 | chat = __.group(1) 109 | else: 110 | chat = m.chat.id 111 | link = args or None 112 | try: 113 | chat = int(chat) 114 | except: 115 | chat = chat 116 | try: 117 | chat = (await m.client.get_entity(chat)).id 118 | except Exception as e: 119 | return await utils.answer(m, self.strings("error").format(str(e))) 120 | else: 121 | chat = m.chat.id 122 | if r and r.audio and not link: 123 | from_file = True 124 | if not link and (not r or not r.audio): 125 | return utils.answer(m, "no audio/link") 126 | if str(chat) not in self.group_calls: 127 | return await utils.answer(m, self.strings("plsjoin")) 128 | self._call(m, chat) 129 | input_file = f"{chat}.raw" 130 | m = await utils.answer(m, self.strings("downloading")) 131 | if from_file: 132 | audio_original = await r.download_media() 133 | else: 134 | try: 135 | with YoutubeDL(self.ytdlopts) as rip: 136 | rip.extract_info(link) 137 | except Exception as e: 138 | return await utils.answer(m, self.strings("error").format(str(e))) 139 | audio_original = "ytdl_out.mp3" 140 | m = await utils.answer(m, self.strings("converting")) 141 | ffmpeg.input(audio_original).output( 142 | input_file, format="s16le", acodec="pcm_s16le", ac=2, ar="48k" 143 | ).overwrite_output().run() 144 | os.remove(audio_original) 145 | await utils.answer(m, self.strings("playing")) 146 | self.group_calls[str(chat)].input_filename = input_file 147 | 148 | async def vjoincmd(self, m: types.Message): 149 | """.vjoin 150 | Join to the VC""" 151 | chat = await self.get_chat(m) 152 | if not chat: 153 | return 154 | self._call(m, chat) 155 | await self.group_calls[str(chat)].start(chat) 156 | await utils.answer(m, self.strings("join")) 157 | 158 | async def vleavecmd(self, m: types.Message): 159 | """.vleave 160 | Leave from the VC""" 161 | chat = await self.get_chat(m) 162 | if not chat: 163 | return 164 | self._call(m, chat) 165 | await self.group_calls[str(chat)].stop() 166 | del self.group_calls[str(chat)] 167 | try: 168 | os.remove(f"{chat}.raw") 169 | except: 170 | pass 171 | await utils.answer(m, self.strings("leave")) 172 | 173 | async def vreplaycmd(self, m: types.Message): 174 | """.vreplay 175 | Replay audio in VC""" 176 | chat = await self.get_chat(m) 177 | if not chat: 178 | return 179 | self._call(m, chat) 180 | self.group_calls[str(chat)].restart_playout() 181 | await utils.answer(m, self.strings("replay")) 182 | 183 | async def vstopcmd(self, m: types.Message): 184 | """.vstop 185 | Stop play in VC""" 186 | chat = await self.get_chat(m) 187 | if not chat: 188 | return 189 | self._call(m, chat) 190 | self.group_calls[str(chat)].stop_playout() 191 | await utils.answer(m, self.strings("stop")) 192 | 193 | async def vmutecmd(self, m: types.Message): 194 | """.vmute 195 | Mute player in VC""" 196 | chat = await self.get_chat(m) 197 | if not chat: 198 | return 199 | self._call(m, chat) 200 | self.group_calls[str(chat)].set_is_mute(True) 201 | await utils.answer(m, self.strings("unmute")) 202 | 203 | async def vunmutecmd(self, m: types.Message): 204 | """.vmute 205 | Unmute player in VC""" 206 | chat = await self.get_chat(m) 207 | if not chat: 208 | return 209 | self._call(m, chat) 210 | self.group_calls[str(chat)].set_is_mute(False) 211 | await utils.answer(m, self.strings("mute")) 212 | 213 | async def vpausecmd(self, m: types.Message): 214 | """.vpause 215 | Pause player in VC""" 216 | chat = await self.get_chat(m) 217 | if not chat: 218 | return 219 | self._call(m, chat) 220 | self.group_calls[str(chat)].pause_playout() 221 | await utils.answer(m, self.strings("pause")) 222 | 223 | async def vresumecmd(self, m: types.Message): 224 | """.vresume 225 | Resume player in VC""" 226 | chat = await self.get_chat(m) 227 | if not chat: 228 | return 229 | self._call(m, chat) 230 | self.group_calls[str(chat)].resume_playout() 231 | await utils.answer(m, self.strings("resume")) 232 | 233 | async def vdebugcmd(self, m: types.Message): 234 | """.vdebug 235 | debug""" 236 | await utils.answer(m, f"DEBUG : {self.group_calls}") 237 | 238 | @loader.unrestricted 239 | async def smcmd(self, message): 240 | """.sm 241 | to find music.""" 242 | args = utils.get_args_raw(message) 243 | reply = await message.get_reply_message() 244 | if not args: 245 | return await utils.answer(message, "No args.") 246 | try: 247 | message = await utils.answer(message, "Loading...") 248 | try: 249 | message = message[0] 250 | except: 251 | pass 252 | music = await self.client.inline_query("lybot", args) 253 | await message.delete() 254 | await self.client.send_file( 255 | message.peer_id, 256 | music[0].result.document, 257 | reply_to=reply.id if reply else None, 258 | ) 259 | except: 260 | return await self.client.send_message( 261 | message.chat_id, 262 | f" Music named {args} not found. ", 263 | ) 264 | 265 | async def shazamcmd(self, message): 266 | """.shazam - recognize track""" 267 | s = await get_audio_shazam(message) 268 | if not s: 269 | return 270 | try: 271 | shazam = Shazam(s.track.read()) 272 | recog = shazam.recognizeSong() 273 | track = next(recog)[1]["track"] 274 | await self.client.send_file( 275 | message.peer_id, 276 | file=track["images"]["background"], 277 | caption=self.tag + "recognized track: " + track["share"]["subject"], 278 | reply_to=s.reply.id, 279 | ) 280 | await message.delete() 281 | except: 282 | await utils.answer(message, self.tag + "Could not recognize...") 283 | 284 | 285 | async def get_audio_shazam(message): 286 | class rct: 287 | track = io.BytesIO() 288 | reply = None 289 | 290 | reply = await message.get_reply_message() 291 | if reply and reply.file and reply.file.mime_type.split("/")[0] == "audio": 292 | ae = rct() 293 | await utils.answer(message, "Downloading...") 294 | ae.track = io.BytesIO(await reply.download_media(bytes)) 295 | ae.reply = reply 296 | await utils.answer(message, "Recognizing...") 297 | return ae 298 | else: 299 | await utils.answer(message, "reply to audio...") 300 | return None 301 | -------------------------------------------------------------------------------- /audio_editor.py: -------------------------------------------------------------------------------- 1 | # Coded by D4n1l3k300 # 2 | # t.me/D4n13l3k00 # 3 | # This code under AGPL-3.0 # 4 | 5 | # requires: pydub numpy requests 6 | 7 | import io 8 | import math 9 | import re 10 | 11 | import numpy as np 12 | import requests 13 | from pydub import AudioSegment, effects 14 | from telethon import types 15 | 16 | from .. import loader, utils 17 | 18 | 19 | @loader.tds 20 | class AudioEditorMod(loader.Module): 21 | """Module for working with sound""" 22 | 23 | strings = { 24 | "name": "AudioEditor", 25 | "downloading": "[{}] Downloading...", 26 | "working": "[{}] Working...", 27 | "exporting": "[{}] Exporting...", 28 | "set_value": "[{}] Specify the level from {} to {}...", 29 | "reply": "[{}] reply to audio...", 30 | "set_fmt": "[{}] Specify the format of output audio...", 31 | "set_time": "[{}] Specify the time in the format start(ms):end(ms)", 32 | } 33 | 34 | @loader.owner 35 | async def basscmd(self, m): 36 | """[level bass'а 2-100 (Default 2)] - BassBoost""" 37 | args = utils.get_args_raw(m) 38 | if not args: 39 | lvl = 2.0 40 | elif re.match(r"^\d+(\.\d+)?$", args) and (1.0 < float(args) < 100.1): 41 | lvl = float(args) 42 | else: 43 | return await utils.answer( 44 | m, self.strings("set_value", m).format("BassBoost", 2.0, 100.0) 45 | ) 46 | audio = await get_audio(self, m, "BassBoost") 47 | if not audio: 48 | return 49 | sample_track = list(audio.audio.get_array_of_samples()) 50 | out = (audio.audio - 0).overlay( 51 | audio.audio.low_pass_filter( 52 | int( 53 | round( 54 | ( 55 | 3 * np.std(sample_track) / (math.sqrt(2)) 56 | - np.mean(sample_track) 57 | ) 58 | * 0.005 59 | ) 60 | ) 61 | ) 62 | + lvl 63 | ) 64 | await go_out(self, m, audio, out, audio.pref, f"{audio.pref} {lvl}lvl") 65 | 66 | @loader.owner 67 | async def fvcmd(self, m): 68 | """[level 2-100 (Default 25)] - Distort""" 69 | args = utils.get_args_raw(m) 70 | if not args: 71 | lvl = 25.0 72 | elif re.match(r"^\d+(\.\d+)?$", args) and (1.0 < float(args) < 100.1): 73 | lvl = float(args) 74 | else: 75 | return await utils.answer( 76 | m, self.strings("set_value", m).format("Distort", 2.0, 100.0) 77 | ) 78 | audio = await get_audio(self, m, "Distort") 79 | if not audio: 80 | return 81 | out = audio.audio + lvl 82 | await go_out(self, m, audio, out, audio.pref, f"{audio.pref} {lvl}lvl") 83 | 84 | @loader.owner 85 | async def echoscmd(self, m): 86 | """ - Echo effect""" 87 | audio = await get_audio(self, m, "Echo") 88 | if not audio: 89 | return 90 | out = AudioSegment.empty() 91 | n = 200 92 | none = io.BytesIO() 93 | out += audio.audio + AudioSegment.from_file(none) 94 | for _ in range(5): 95 | out = out.overlay(audio.audio, n) 96 | n += 200 97 | await go_out(self, audio.message, audio, out, audio.pref, audio.pref) 98 | 99 | @loader.owner 100 | async def volupcmd(self, m): 101 | """ - VolUp 10dB""" 102 | audio = await get_audio(self, m, "+10dB") 103 | if not audio: 104 | return 105 | out = audio.audio + 10 106 | await go_out(self, audio.message, audio, out, audio.pref, audio.pref) 107 | 108 | @loader.owner 109 | async def voldwcmd(self, m): 110 | """ - VolDw 10dB""" 111 | audio = await get_audio(self, m, "-10dB") 112 | if not audio: 113 | return 114 | out = audio.audio - 10 115 | await go_out(self, audio.message, audio, out, audio.pref, audio.pref) 116 | 117 | @loader.owner 118 | async def revscmd(self, m): 119 | """ - Reverse audio""" 120 | audio = await get_audio(self, m, "Reverse") 121 | if not audio: 122 | return 123 | out = audio.audio.reverse() 124 | await go_out(self, audio.message, audio, out, audio.pref, audio.pref) 125 | 126 | @loader.owner 127 | async def repscmd(self, m): 128 | """ - Repeat audio 2 times""" 129 | audio = await get_audio(self, m, "Repeat") 130 | if not audio: 131 | return 132 | out = audio.audio * 2 133 | await go_out(self, audio.message, audio, out, audio.pref, audio.pref) 134 | 135 | @loader.owner 136 | async def slowscmd(self, m): 137 | """ - SlowDown 0.5x""" 138 | audio = await get_audio(self, m, "SlowDown") 139 | if not audio: 140 | return 141 | s2 = audio.audio._spawn( 142 | audio.audio.raw_data, 143 | overrides={"frame_rate": int(audio.audio.frame_rate * 0.5)}, 144 | ) 145 | out = s2.set_frame_rate(audio.audio.frame_rate) 146 | await go_out( 147 | self, audio.message, audio, out, audio.pref, audio.pref, audio.duration * 2 148 | ) 149 | 150 | @loader.owner 151 | async def fastscmd(self, m): 152 | """ - SpeedUp 1.5x""" 153 | audio = await get_audio(self, m, "SpeedUp") 154 | if not audio: 155 | return 156 | s2 = audio.audio._spawn( 157 | audio.audio.raw_data, 158 | overrides={"frame_rate": int(audio.audio.frame_rate * 1.5)}, 159 | ) 160 | out = s2.set_frame_rate(audio.audio.frame_rate) 161 | await go_out( 162 | self, 163 | audio.message, 164 | audio, 165 | out, 166 | audio.pref, 167 | audio.pref, 168 | round(audio.duration / 2), 169 | ) 170 | 171 | @loader.owner 172 | async def rightscmd(self, m): 173 | """ - Push sound to right channel""" 174 | audio = await get_audio(self, m, "Right channel") 175 | if not audio: 176 | return 177 | out = effects.pan(audio.audio, +1.0) 178 | await go_out(self, audio.message, audio, out, audio.pref, audio.pref) 179 | 180 | @loader.owner 181 | async def leftscmd(self, m): 182 | """ - Push sound to left channel""" 183 | audio = await get_audio(self, m, "Left channel") 184 | if not audio: 185 | return 186 | out = effects.pan(audio.audio, -1.0) 187 | await go_out(self, audio.message, audio, out, audio.pref, audio.pref) 188 | 189 | @loader.owner 190 | async def normscmd(self, m): 191 | """ - Normalize sound (from quiet to normal)""" 192 | audio = await get_audio(self, m, "Normalization") 193 | if not audio: 194 | return 195 | out = effects.normalize(audio.audio) 196 | await go_out(self, audio.message, audio, out, audio.pref, audio.pref) 197 | 198 | @loader.owner 199 | async def tovscmd(self, m): 200 | """ - Convert to voice message""" 201 | audio = await get_audio(self, m, "Voice") 202 | if not audio: 203 | return 204 | audio.voice = True 205 | await go_out(self, audio.message, audio, audio.audio, audio.pref, audio.pref) 206 | 207 | @loader.owner 208 | async def convscmd(self, m): 209 | """ [audio_format (ex. `mp3`)] - Convert audio to some format""" 210 | f = utils.get_args(m) 211 | if not f: 212 | return await utils.answer(m, self.strings("set_fmt", m).format("Converter")) 213 | audio = await get_audio(self, m, "Converter") 214 | if not audio: 215 | return 216 | await go_out( 217 | self, 218 | audio.message, 219 | audio, 220 | audio.audio, 221 | audio.pref, 222 | f"Converted to {f[0].lower()}", 223 | fmt=f[0].lower(), 224 | ) 225 | 226 | @loader.owner 227 | async def byrobertscmd(self, m): 228 | ''' - Add at the end "Directed by Robert B Weide"''' 229 | audio = await get_audio(self, m, "Directed by...") 230 | if not audio: 231 | return 232 | out = audio.audio + AudioSegment.from_file( 233 | io.BytesIO( 234 | requests.get( 235 | "https://raw.githubusercontent.com/D4n13l3k00/files-for-modules/master/directed.mp3" 236 | ).content 237 | ) 238 | ).apply_gain(+8) 239 | await go_out(self, audio.message, audio, out, audio.pref, audio.pref) 240 | 241 | @loader.owner 242 | async def cutscmd(self, m): 243 | """ - Cut audio""" 244 | args = utils.get_args_raw(m) 245 | if not args: 246 | return await utils.answer(m, self.strings("set_time", m).format("Cut")) 247 | r = re.compile(r"^(?P\d+){0,1}:(?P\d+){0,1}$") 248 | ee = r.match(args) 249 | if not ee: 250 | return await utils.answer(m, self.strings("set_time", m).format("Cut")) 251 | start = int(ee.group("start")) if ee.group("start") else 0 252 | end = int(ee.group("end")) if ee.group("end") else 0 253 | audio = await get_audio(self, m, "Cut") 254 | if not audio: 255 | return 256 | out = audio.audio[start : end or len(audio.audio) - 1] 257 | await go_out(self, audio.message, audio, out, audio.pref, audio.pref) 258 | 259 | 260 | class AudioEditorClass: 261 | audio = None 262 | message = None 263 | duration = None 264 | voice = None 265 | pref = None 266 | reply = None 267 | 268 | 269 | async def get_audio(self, m, pref): 270 | 271 | r = await m.get_reply_message() 272 | if r and r.file and r.file.mime_type.split("/")[0] in ["audio", "video"]: 273 | ae = AudioEditorClass() 274 | ae.pref = pref 275 | ae.reply = r 276 | ae.voice = ( 277 | r.document.attributes[0].voice 278 | if r.file.mime_type.split("/")[0] == "audio" 279 | else False 280 | ) 281 | ae.duration = r.document.attributes[0].duration 282 | ae.message = await utils.answer(m, self.strings("downloading", m).format(pref)) 283 | ae.audio = AudioSegment.from_file(io.BytesIO(await r.download_media(bytes))) 284 | ae.message = await utils.answer( 285 | ae.message, self.strings("working", m).format(pref) 286 | ) 287 | return ae 288 | await utils.answer(m, self.strings("reply", m).format(pref)) 289 | return None 290 | 291 | 292 | async def go_out(self, m, audio, out, pref, title, fs=None, fmt="mp3"): 293 | o = io.BytesIO() 294 | o.name = "audio." + ("ogg" if audio.voice else "mp3") 295 | if audio.voice: 296 | out.split_to_mono() 297 | m = await utils.answer(m, self.strings("exporting").format(pref)) 298 | out.export( 299 | o, 300 | format="ogg" if audio.voice else fmt, 301 | bitrate="64k" if audio.voice else None, 302 | codec="libopus" if audio.voice else None, 303 | ) 304 | o.seek(0) 305 | await utils.answer( 306 | m, 307 | o, 308 | reply_to=audio.reply.id, 309 | voice_note=audio.voice, 310 | attributes=[ 311 | types.DocumentAttributeAudio( 312 | duration=fs or audio.duration, 313 | title=title, 314 | performer="AudioEditor", 315 | ) 316 | ] 317 | if not audio.voice 318 | else None, 319 | ) 320 | --------------------------------------------------------------------------------