diff --git a/hikka/inline/token_obtainment.py b/hikka/inline/token_obtainment.py index 9fae9f7..ef5b1fe 100644 --- a/hikka/inline/token_obtainment.py +++ b/hikka/inline/token_obtainment.py @@ -27,15 +27,30 @@ class TokenObtainment(InlineUnit): m = await conv.send_message("/newbot") r = await conv.get_response() + logger.debug(f">> {m.raw_text}") + logger.debug(f"<< {r.raw_text}") + if "20" in r.raw_text: return False await m.delete() await r.delete() - # Generate and set random username for bot - uid = utils.rand(6) - username = f"hikka_{uid}_bot" + if self._db.get("hikka.inline", "custom_bot", False): + username = self._db.get("hikka.inline", "custom_bot").strip("@") + username = f"@{username}" + try: + await self._client.get_entity(username) + except ValueError: + pass + else: + # Generate and set random username for bot + uid = utils.rand(6) + username = f"@hikka_{uid}_bot" + else: + # Generate and set random username for bot + uid = utils.rand(6) + username = f"@hikka_{uid}_bot" for msg in [ f"👩‍🎤 Hikka Userbot of {self._name}", @@ -116,84 +131,95 @@ class TokenObtainment(InlineUnit): for row in r.reply_markup.rows: for button in row.buttons: - if re.search(r"@hikka_[0-9a-zA-Z]{6}_bot", button.text): + if ( + self._db.get("hikka.inline", "custom_bot", False) + and self._db.get("hikka.inline", "custom_bot", False) + != button.text.strip("@") + ): + continue + + if not self._db.get( + "hikka.inline", "custom_bot", False + ) and not re.search(r"@hikka_[0-9a-zA-Z]{6}_bot", button.text): + continue + + m = await conv.send_message(button.text) + r = await conv.get_response() + + logger.debug(f">> {m.raw_text}") + logger.debug(f"<< {r.raw_text}") + + if revoke_token: + await m.delete() + await r.delete() + + m = await conv.send_message("/revoke") + r = await conv.get_response() + + logger.debug(f">> {m.raw_text}") + logger.debug(f"<< {r.raw_text}") + + await m.delete() + await r.delete() + m = await conv.send_message(button.text) r = await conv.get_response() logger.debug(f">> {m.raw_text}") logger.debug(f"<< {r.raw_text}") - if revoke_token: - await m.delete() - await r.delete() + token = r.raw_text.splitlines()[1] - m = await conv.send_message("/revoke") - r = await conv.get_response() + # Save token to database, now this bot is ready-to-use + self._db.set("hikka.inline", "bot_token", token) + self._token = token - logger.debug(f">> {m.raw_text}") - logger.debug(f"<< {r.raw_text}") + await m.delete() + await r.delete() - await m.delete() - await r.delete() + # Enable inline mode or change its + # placeholder in case it is not set - m = await conv.send_message(button.text) - r = await conv.get_response() + for msg in [ + "/setinline", + button.text, + "HikkaQuery", + "/setinlinefeedback", + button.text, + "Enabled", + "/setuserpic", + button.text, + ]: + m = await conv.send_message(msg) + r = await conv.get_response() - logger.debug(f">> {m.raw_text}") - logger.debug(f"<< {r.raw_text}") - - token = r.raw_text.splitlines()[1] - - # Save token to database, now this bot is ready-to-use - self._db.set("hikka.inline", "bot_token", token) - self._token = token + logger.debug(f">> {m.raw_text}") + logger.debug(f"<< {r.raw_text}") await m.delete() await r.delete() - # Enable inline mode or change its - # placeholder in case it is not set + try: + m = await conv.send_file(photo) + r = await conv.get_response() - for msg in [ - "/setinline", - button.text, - "HikkaQuery", - "/setinlinefeedback", - button.text, - "Enabled", - "/setuserpic", - button.text, - ]: - m = await conv.send_message(msg) - r = await conv.get_response() + logger.debug(">> ") + logger.debug(f"<< {r.raw_text}") + except Exception: + # In case user was not able to send photo to + # BotFather, it is not a critical issue, so + # just ignore it + m = await conv.send_message("/cancel") + r = await conv.get_response() - logger.debug(f">> {m.raw_text}") - logger.debug(f"<< {r.raw_text}") + logger.debug(f">> {m.raw_text}") + logger.debug(f"<< {r.raw_text}") - await m.delete() - await r.delete() + await m.delete() + await r.delete() - try: - m = await conv.send_file(photo) - r = await conv.get_response() - - logger.debug(">> ") - logger.debug(f"<< {r.raw_text}") - except Exception: - # In case user was not able to send photo to - # BotFather, it is not a critical issue, so - # just ignore it - m = await conv.send_message("/cancel") - r = await conv.get_response() - - logger.debug(f">> {m.raw_text}") - logger.debug(f"<< {r.raw_text}") - - await m.delete() - await r.delete() - - # Return `True` to say, that everything is okay - return True + # Return `True` to say, that everything is okay + return True # And we are not returned after creation return await self._create_bot() if create_new_if_needed else False diff --git a/hikka/modules/inline_stuff.py b/hikka/modules/inline_stuff.py index d08cff6..0182bc1 100644 --- a/hikka/modules/inline_stuff.py +++ b/hikka/modules/inline_stuff.py @@ -18,6 +18,9 @@ from aiogram.types import CallbackQuery import logging import re +from telethon.errors.rpcerrorlist import YouBlockedUserError +from telethon.tl.functions.contacts import UnblockRequest + logger = logging.getLogger(__name__) @@ -25,7 +28,12 @@ logger = logging.getLogger(__name__) class InlineStuffMod(loader.Module): """Provides support for inline stuff""" - strings = {"name": "InlineStuff"} + strings = { + "name": "InlineStuff", + "bot_username_invalid": "🚫 Specified bot username is invalid. It must end with bot and contain at least 4 symbols", + "bot_username_occupied": "🚫 This username is already occupied", + "bot_updated": "😌 Config successfully saved. Restart userbot to apply changes", + } async def client_ready(self, client, db) -> None: self._db = db @@ -55,3 +63,52 @@ class InlineStuffMod(loader.Module): ) await message.delete() + + async def _check_bot(self, username: str) -> bool: + async with self._client.conversation("@BotFather", exclusive=False) as conv: + try: + m = await conv.send_message("/token") + except YouBlockedUserError: + await self._client(UnblockRequest(id="@BotFather")) + m = await conv.send_message("/token") + + r = await conv.get_response() + + await m.delete() + await r.delete() + + if not hasattr(r, "reply_markup") or not hasattr(r.reply_markup, "rows"): + return False + + for row in r.reply_markup.rows: + for button in row.buttons: + if username != button.text.strip("@"): + continue + + m = await conv.send_message("/cancel") + r = await conv.get_response() + + await m.delete() + await r.delete() + + return True + + async def ch_hikka_botcmd(self, message: Message) -> None: + """ - Change your Hikka inline bot username""" + args = utils.get_args_raw(message).strip("@") + if not args or not args.endswith("bot") or len(args) <= 4: + await utils.answer(message, self.strings("bot_username_invalid")) + return + + try: + await self._client.get_entity(f"@{args}") + except ValueError: + pass + else: + if not await self._check_bot(args): + await utils.answer(message, self.strings("bot_username_occupied")) + return + + self._db.set("hikka.inline", "custom_bot", args) + self._db.set("hikka.inline", "bot_token", None) + await utils.answer(message, self.strings("bot_updated"))