from telethon.tl.functions.messages import ExportChatInviteRequest, EditExportedChatInviteRequest from telethon.types import Message from .. import loader, utils from ..inline.types import InlineCall import logging import datetime """ ███ ███ ██ ██ ██████ ██ ██ ██ ██████ ███████ ███████ ████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██████ ██ ██ ██ ██ ██ ███████ █████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██████ ██ ██ ██████ ███████ ██████ ███████ ███████ Module Name """ # scopes: # 🔒 Licensed under the GNU AGPLv3 # meta banner: https://raw.githubusercontent.com/MuRuLOSE/HikkaModulesRepo/main/assets/modbanners/inumber.png # meta desc: Manage Telegram invite links # meta developer: @BruhHikkaModules logger = logging.getLogger(__name__) @loader.tds class InviteManager(loader.Module): """Manage Telegram invite links""" strings = { "name": "InviteManager", "no_args": " No arguments provided", "no_channel": " Please specify a channel or use in a channel", "created": " Invite link created: {link}", "select_action": "Select an action for the invite link: {link}", "revoked": " Invite link revoked", "select_expiry": "Select expiration period for the invite link: {link}", "select_limit": "Select usage limit for the invite link: {link}", "updated_expiry": " Expiry updated to {date}", "updated_limit": " Usage limit updated to {limit}", "invalid_date": " Invalid date format. Use YYYY-MM-DD HH:MM", "invalid_limit": " Invalid number for usage limit", "invalid_link": " Invalid invite link", "chat_required": " Please use this command in the target channel or specify the channel", } strings_ru = { "no_args": " Аргументы не указаны", "no_channel": " Укажите канал или используйте в канале", "created": " Ссылка-приглашение создана: {link}", "select_action": "Выберите действие для ссылки: {link}", "revoked": " Ссылка отозвана", "select_expiry": "Выберите период действия для ссылки: {link}", "select_limit": "Выберите лимит использований для ссылки: {link}", "updated_expiry": " Дата истечения обновлена: {date}", "updated_limit": " Лимит использований обновлен: {limit}", "invalid_date": " Неверный формат даты. Используйте ГГГГ-ММ-ДД ЧЧ:ММ", "invalid_limit": " Неверное число для лимита", "invalid_link": " Неверная ссылка-приглашение", "chat_required": " Используйте команду в целевом канале или укажите канал", } async def client_ready(self, client, db): self.client = client self.db = db @loader.command(ru_doc="Создать ссылку-приглашение для канала") async def createinvite(self, message: Message): """Create an invite link for a channel""" args = utils.get_args_raw(message) chat = None if args: try: chat = await self.client.get_entity(args) except Exception as e: logger.error(f"Failed to get entity: {e}") await utils.answer(message, self.strings["no_channel"]) return else: if message.is_channel or message.is_group: chat = message.peer_id else: await utils.answer(message, self.strings["no_channel"]) return try: result = await self.client( ExportChatInviteRequest( peer=chat, legacy_revoke_permanent=False, request_needed=False, title="Invite Link" ) ) link = result.link await utils.answer(message, self.strings["created"].format(link=link)) except Exception as e: logger.error(f"Error creating invite: {e}") await utils.answer(message, " Failed to create invite link") @loader.command(ru_doc="[ссылка] [канал] - Редактировать ссылку-приглашение через инлайн-кнопки") async def editinvite(self, message: Message): """[link] [channel] - Edit an invite link with inline buttons""" args = utils.get_args_split_by(message, separator=" ") if len(args) < 2: if message.is_channel or message.is_group: chat = message.peer_id link = args[0] if args else None else: await utils.answer(message, self.strings["chat_required"]) return else: link, chat_arg = args[0], args[1] try: chat = await self.client.get_entity(chat_arg) except Exception as e: logger.error(f"Failed to get entity: {e}") await utils.answer(message, self.strings["no_channel"]) return if not link: await utils.answer(message, self.strings["no_args"]) return try: if not link.startswith("https://t.me/"): raise ValueError("Invalid invite link") await self.inline.form( message=message, text=self.strings["select_action"].format(link=link), reply_markup=[ [ {"text": "Revoke", "callback": self._revoke_link, "args": (link, chat)}, {"text": "Set Expiry", "callback": self._prompt_expiry, "args": (link, chat)}, ], [ {"text": "Set Usage Limit", "callback": self._prompt_limit, "args": (link, chat)}, ] ] ) except Exception as e: logger.error(f"Error initiating edit: {e}") await utils.answer(message, self.strings["invalid_link"]) async def _revoke_link(self, call: InlineCall, link: str, chat): try: await self.client( EditExportedChatInviteRequest( peer=chat, link=link, revoked=True ) ) await call.edit( text=self.strings["revoked"], reply_markup=[[{"text": "Back", "callback": self._back_to_menu, "args": (link, chat)}]] ) except Exception as e: logger.error(f"Error revoking link: {e}") await call.edit( text=" Failed to revoke link", reply_markup=[[{"text": "Back", "callback": self._back_to_menu, "args": (link, chat)}]] ) async def _prompt_expiry(self, call: InlineCall, link: str, chat): await call.edit( text=self.strings["select_expiry"].format(link=link), reply_markup=[ [ {"text": "1 Hour", "callback": self._set_expiry, "args": (link, chat, 1, "hours")}, {"text": "1 Day", "callback": self._set_expiry, "args": (link, chat, 1, "days")}, ], [ {"text": "1 Week", "callback": self._set_expiry, "args": (link, chat, 1, "weeks")}, {"text": "1 Month", "callback": self._set_expiry, "args": (link, chat, 1, "months")}, ], [ {"text": "No Expiry", "callback": self._set_expiry, "args": (link, chat, None, None)}, {"text": "Cancel", "callback": self._back_to_menu, "args": (link, chat)}, ] ] ) async def _set_expiry(self, call: InlineCall, link: str, chat, value: int, unit: str): expiry_date = None if value is not None and unit is not None: try: now = datetime.datetime.now() if unit == "hours": expiry_date = now + datetime.timedelta(hours=value) elif unit == "days": expiry_date = now + datetime.timedelta(days=value) elif unit == "weeks": expiry_date = now + datetime.timedelta(weeks=value) elif unit == "months": expiry_date = now + datetime.timedelta(days=value * 30) # Approximate month except Exception as e: logger.error(f"Error calculating expiry: {e}") await call.edit( text=self.strings["invalid_date"], reply_markup=[[{"text": "Back", "callback": self._back_to_menu, "args": (link, chat)}]] ) return try: await self.client( EditExportedChatInviteRequest( peer=chat, link=link, expire_date=expiry_date ) ) expiry_text = expiry_date.strftime("%Y-%m-%d %H:%M") if expiry_date else "no expiry" await call.edit( text=self.strings["updated_expiry"].format(date=expiry_text), reply_markup=[[{"text": "Back", "callback": self._back_to_menu, "args": (link, chat)}]] ) except Exception as e: logger.error(f"Error setting expiry: {e}") await call.edit( text=" Failed to update expiry", reply_markup=[[{"text": "Back", "callback": self._back_to_menu, "args": (link, chat)}]] ) async def _prompt_limit(self, call: InlineCall, link: str, chat): await call.edit( text=self.strings["select_limit"].format(link=link), reply_markup=[ [ {"text": "1 Use", "callback": self._set_limit, "args": (link, chat, 1)}, {"text": "10 Uses", "callback": self._set_limit, "args": (link, chat, 10)}, ], [ {"text": "50 Uses", "callback": self._set_limit, "args": (link, chat, 50)}, {"text": "100 Uses", "callback": self._set_limit, "args": (link, chat, 100)}, ], [ {"text": "Unlimited", "callback": self._set_limit, "args": (link, chat, None)}, {"text": "Cancel", "callback": self._back_to_menu, "args": (link, chat)}, ] ] ) async def _set_limit(self, call: InlineCall, link: str, chat, usage_limit: int): try: await self.client( EditExportedChatInviteRequest( peer=chat, link=link, usage_limit=usage_limit ) ) limit_text = str(usage_limit) if usage_limit is not None else "unlimited" await call.edit( text=self.strings["updated_limit"].format(limit=limit_text), reply_markup=[[{"text": "Back", "callback": self._back_to_menu, "args": (link, chat)}]] ) except Exception as e: logger.error(f"Error setting limit: {e}") await call.edit( text=" Failed to update limit", reply_markup=[[{"text": "Back", "callback": self._back_to_menu, "args": (link, chat)}]] ) async def _back_to_menu(self, call: InlineCall, link: str, chat): await call.edit( text=self.strings["select_action"].format(link=link), reply_markup=[ [ {"text": "Revoke", "callback": self._revoke_link, "args": (link, chat)}, {"text": "Set Expiry", "callback": self._prompt_expiry, "args": (link, chat)}, ], [ {"text": "Set Usage Limit", "callback": self._prompt_limit, "args": (link, chat)}, ] ] )