# TG-UserBot - A modular Telegram UserBot script for Python. # Copyright (C) 2019 Kandarp <https://github.com/kandnub> # # TG-UserBot is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # TG-UserBot is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with TG-UserBot. If not, see <https://www.gnu.org/licenses/>. import io import PIL from telethon import errors from telethon.utils import get_display_name, get_peer_id from telethon.tl import functions, types from userbot import client, LOGGER from userbot.helper_funcs.parser import Parser from userbot.utils.events import NewMessage plugin_category = "user" @client.onMessage( command=("whois", plugin_category), outgoing=True, regex=r"(?:who|what)is(?: |$|\n)([\s\S]*)" ) async def whois(event: NewMessage.Event) -> None: """ Get your or a user's/chat's information. `{prefix}whois` or **{prefix}whois user1 id1 user2 id2** This works for channels and groups too. """ match = event.matches[0].group(1) entities = [] if match: entities, _ = await client.parse_arguments(match) if "this" in entities: entities.remove("this") entities.append(event.chat_id) elif event.reply_to_msg_id: if not entities: reply = await event.get_reply_message() user = reply.sender_id if reply.fwd_from: if reply.fwd_from.from_id: user = reply.fwd_from.from_id entities.append(user) else: entities.append("self") users = "" chats = "" channels = "" failed = [] for user in entities: try: input_entity = await client.get_input_entity(user) if isinstance(input_entity, types.InputPeerChat): full_chat = await client( functions.messages.GetFullChatRequest(input_entity) ) string = await Parser.parse_full_chat(full_chat, event) chats += f"\n{chats}\n" elif isinstance(input_entity, types.InputPeerChannel): full_channel = await client( functions.channels.GetFullChannelRequest(input_entity) ) string = await Parser.parse_full_chat(full_channel, event) channels += f"\n{string}\n" else: full_user = await client( functions.users.GetFullUserRequest(input_entity) ) string = await Parser.parse_full_user(full_user, event) users += f"\n{string}\n" except Exception as e: LOGGER.debug(e) failed.append(user) if users: await event.answer("**USERS**" + users, reply=True) if chats: await event.answer("**CHATS**" + chats, reply=True) if channels: await event.answer("**CHANNELS**" + channels, reply=True) if failed: failedtext = "**Unable to fetch:**\n" failedtext += ", ".join(f'`{u}`' for u in failed) await event.answer(failedtext) elif not (users or chats or channels): await event.answer("__Something went wrong!__", self_destruct=2) @client.onMessage( command=("name", plugin_category), outgoing=True, regex="name(?: |$)(.*)$" ) async def name(event: NewMessage.Event) -> None: """ Get your current name or update it. `{prefix}name` or **{prefix}name (first) [(last)]** The name will be split from the first space unless args are used. **Arguments:** `first` and `last` """ match = event.matches[0].group(1) or '' me = await client.get_me() if not match: text = f"**First name:** `{me.first_name}`" if me.last_name: text += f"\n**Last name:** `{me.last_name}`" await event.answer(text) return _, kwargs = await client.parse_arguments(match) if kwargs: first = kwargs.get('first', me.first_name) last = kwargs.get('last', me.last_name) else: split = match.strip().split(maxsplit=1) if len(split) > 1: first, last = split else: first = split[0] last = me.last_name n1 = get_display_name(me) try: await client(functions.account.UpdateProfileRequest( first_name=first, last_name=last )) n2 = get_display_name(await client.get_me()) await event.answer( f"`Name was successfully changed to {n2}.`", log=("name", f"Name changed from {n1} to {n2}") ) except errors.FirstNameInvalidError: await event.answer("`The first name is invalid.`") except Exception as e: await event.answer(f'```{await client.get_traceback(e)}```') @client.onMessage( command=("bio", plugin_category), outgoing=True, regex="bio(?: |$)(.*)$" ) async def bio(event: NewMessage.Event) -> None: """ Get your current bio or update it. `{prefix}bio` or **{prefix}bio (text)** """ match = event.matches[0].group(1) about = (await client(functions.users.GetFullUserRequest("self"))).about if not match: if about: await event.answer(f"**{about}**") else: await event.answer("`You currently have no bio.`") return try: await client(functions.account.UpdateProfileRequest(about=match)) await event.answer( f"`Bio was successfully changed to {match}.`", log=("bio", f"Bio changed from {about} to {match}") ) except errors.AboutTooLongError: await event.answer("`The about text is too long.`") @client.onMessage( command=("username", plugin_category), outgoing=True, regex="username(?: |$)(.*)$" ) async def username(event: NewMessage.Event) -> None: """ Get your current username or update it. `{prefix}username` or **{prefix}username (new username)** """ match = event.matches[0].group(1) u1 = (await client.get_me()).username if not match: if u1: await event.answer(f"**{u1}**") else: await event.answer("`You currently have no username.`") return try: await client(functions.account.UpdateUsernameRequest(username=match)) await event.answer( f"`Username was successfully changed to {match}`", log=("username", f"Username changed from {u1} to {match}") ) except errors.UsernameOccupiedError: await event.answer("`The username is already in use.`") except errors.UsernameNotModifiedError: await event.answer("`The username was not modified.`") except errors.UsernameInvalidError: await event.answer("`The username is invalid.`") @client.onMessage( command=("pfp", plugin_category), outgoing=True, regex="pfp$" ) async def pfp(event: NewMessage.Event) -> None: """ Get your current profile picture or update it. `{prefix}pfp` in reply to an image """ reply = await event.get_reply_message() if not reply: photo = await client(functions.users.GetFullUserRequest("self")) photo = photo.profile_photo if photo: await event.delete() await event.answer(file=photo) else: await event.answer("`You currently have no profile picture.`") return if not reply.media: await event.answer( "`What do I use to update the profile picture, a text?`" ) return if ( (reply.document and reply.document.mime_type.startswith("image")) or reply.photo or reply.sticker ): if reply.sticker and not reply.sticker.mime_type == "image/webp": await event.answer("`Invalid sticker type.`") return try: temp_file = io.BytesIO() await client.download_media(reply, temp_file) except Exception as e: await event.answer( f'```{await client.get_traceback(e)}```', reply=True ) temp_file.close() return temp_file.seek(0) if reply.sticker: sticker = io.BytesIO() pilImg = PIL.Image.open(temp_file) pilImg.save(sticker, format="PNG") pilImg.close() sticker.seek(0) sticker.name = "sticcer.png" photo = await client.upload_file(sticker) temp_file.close() sticker.close() else: photo = await client.upload_file(temp_file) temp_file.close() else: await event.answer("`Invalid media type.`") return try: await client(functions.photos.UploadProfilePhotoRequest(photo)) await event.answer( "`Profile photo was successfully changed.`", log=("pfp", "Changed profile picture") ) except errors.FilePartsInvalidError: await event.answer("`The number of file parts is invalid.`") except errors.ImageProcessFailedError: await event.answer("`Failure while processing image.`") except errors.PhotoCropSizeSmallError: await event.answer("`Photo is too small.`") except errors.PhotoExtInvalidError: await event.answer("`The extension of the photo is invalid.`") @client.onMessage( command=("delpfp", plugin_category), outgoing=True, regex=r"delpfp(?: |$)(\d*|all)$" ) async def delpfp(event: NewMessage.Event) -> None: """ Get your current profile picture count or delete them. `{prefix}delpfp` or `{prefix}delpfp all` or **{prefix}delpfp (amount)** """ match = event.matches[0].group(1) if not match: count = (await client.get_profile_photos("self")).total amount = ("one profile picture." if count == 1 else f"{count} profile pictures.") await event.answer(f"`You currently have {amount}`") return await event.answer("`Processing all the profile pictures...`") limit = None if match == "all" else int(match) photos = await client.get_profile_photos("self", limit) count = len(photos) await client(functions.photos.DeletePhotosRequest(photos)) amount = ("the current profile picture." if count == 1 else f"{count} profile pictures.") text = f"`Successfully deleted {amount}`" await event.answer( text, log=("delpfp", f"Deleted {count} profile picture(s)") ) @client.onMessage( command=("id", plugin_category), outgoing=True, regex=r"id(?: |$|\n)([\s\S]*)" ) async def whichid(event: NewMessage.Event) -> None: """ Get the ID of a chat/channel or user. `{prefix}id` or **{prefix}id user1 user2** """ match = event.matches[0].group(1) text = "" if not match and not event.reply_to_msg_id: attr = "first_name" if event.is_private else "title" text = f"{getattr(event.chat, attr)}: " text += f"`{get_peer_id(event.chat_id)}`" elif event.reply_to_msg_id: reply = await event.get_reply_message() user = reply.sender_id if reply.fwd_from: if reply.fwd_from.from_id: user = reply.fwd_from.from_id peer = get_peer_id(user) text = f"[{peer}](tg://user?id={peer}): `{peer}`" else: failed = [] strings = [] users, _ = await client.parse_arguments(match) for user in users: try: entity = await client.get_input_entity(user) peer = get_peer_id(entity) strings.append( f"[{user}](tg://user?id={peer}): `{peer}`" ) except Exception as e: failed.append(user) LOGGER.debug(e) if strings: text = ",\n".join(strings) if failed: ftext = "**Users which weren't resolved:**\n" ftext += ", ".join(f'`{f}`' for f in failed) await event.answer(ftext, reply=True) if text: await event.answer(text)