mirror of https://github.com/coddrago/Heroku
210 lines
6.9 KiB
Python
210 lines
6.9 KiB
Python
"""Inline buttons, galleries and other Telegram-Bot-API stuff"""
|
|
|
|
# █ █ ▀ █▄▀ ▄▀█ █▀█ ▀ ▄▀█ ▀█▀ ▄▀█ █▀▄▀█ ▄▀█
|
|
# █▀█ █ █ █ █▀█ █▀▄ █ ▄ █▀█ █ █▀█ █ ▀ █ █▀█
|
|
#
|
|
# © Copyright 2022
|
|
#
|
|
# https://t.me/hikariatama
|
|
#
|
|
# 🔒 Licensed under the GNU GPLv3
|
|
# 🌐 https://www.gnu.org/licenses/agpl-3.0.html
|
|
|
|
import asyncio
|
|
import logging
|
|
import time
|
|
|
|
from aiogram import Bot, Dispatcher
|
|
from aiogram.types import ParseMode
|
|
from aiogram.utils.exceptions import TerminatedByOtherGetUpdates, Unauthorized
|
|
from telethon.errors.rpcerrorlist import InputUserDeactivatedError, YouBlockedUserError
|
|
from telethon.tl.functions.contacts import UnblockRequest
|
|
from telethon.utils import get_display_name
|
|
|
|
from ..database import Database
|
|
from .bot_pm import BotPM
|
|
from .events import Events
|
|
from .form import Form
|
|
from .gallery import Gallery
|
|
from .list import List
|
|
from .query_gallery import QueryGallery
|
|
from .token_obtainment import TokenObtainment
|
|
from .utils import Utils
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class InlineManager(
|
|
Utils,
|
|
Events,
|
|
TokenObtainment,
|
|
Form,
|
|
Gallery,
|
|
QueryGallery,
|
|
List,
|
|
BotPM,
|
|
):
|
|
def __init__(
|
|
self,
|
|
client: "TelegramClient", # noqa: F821
|
|
db: Database,
|
|
allmodules: "Modules", # noqa: F821
|
|
):
|
|
"""Initialize InlineManager to create forms"""
|
|
self._client = client
|
|
self._db = db
|
|
self._allmodules = allmodules
|
|
|
|
self._token = db.get("hikka.inline", "bot_token", False)
|
|
|
|
self._forms = {}
|
|
self._galleries = {}
|
|
self._lists = {}
|
|
self._custom_map = {}
|
|
|
|
self.fsm = {}
|
|
|
|
self._web_auth_tokens = []
|
|
|
|
self._markup_ttl = 60 * 60 * 24
|
|
|
|
self.init_complete = False
|
|
|
|
async def _cleaner(self):
|
|
"""Cleans outdated _forms"""
|
|
while True:
|
|
for form_uid, form in self._forms.copy().items():
|
|
if form.get("ttl", time.time() + self._markup_ttl) < time.time():
|
|
del self._forms[form_uid]
|
|
|
|
for gallery_uid, gallery in self._galleries.copy().items():
|
|
if gallery.get("ttl", time.time() + self._markup_ttl) < time.time():
|
|
del self._galleries[gallery_uid]
|
|
|
|
for map_uid, config in self._custom_map.copy().items():
|
|
if config.get("ttl", time.time() + self._markup_ttl) < time.time():
|
|
del self._custom_map[map_uid]
|
|
|
|
await asyncio.sleep(5)
|
|
|
|
async def _register_manager(
|
|
self,
|
|
after_break: bool = False,
|
|
ignore_token_checks: bool = False,
|
|
):
|
|
# Get info about user to use it in this class
|
|
me = await self._client.get_me()
|
|
self._me = me.id
|
|
self._name = get_display_name(me)
|
|
|
|
if not ignore_token_checks:
|
|
# Assert that token is set to valid, and if not,
|
|
# set `init_complete` to `False` and return
|
|
is_token_asserted = await self._assert_token()
|
|
if not is_token_asserted:
|
|
self.init_complete = False
|
|
return
|
|
|
|
# We successfully asserted token, so set `init_complete` to `True`
|
|
self.init_complete = True
|
|
|
|
# Create bot instance and dispatcher
|
|
self.bot = Bot(token=self._token, parse_mode=ParseMode.HTML)
|
|
self._bot = self.bot # This is a temporary alias so the
|
|
# developers can adapt their code
|
|
self._dp = Dispatcher(self.bot)
|
|
|
|
# Get bot username to call inline queries
|
|
try:
|
|
self.bot_username = (await self.bot.get_me()).username
|
|
self.bot_id = (await self.bot.get_me()).id
|
|
except Unauthorized:
|
|
logger.critical("Token expired, revoking...")
|
|
return await self._dp_revoke_token(False)
|
|
|
|
# Start the bot in case it can send you messages
|
|
try:
|
|
m = await self._client.send_message(self.bot_username, "/start")
|
|
except (InputUserDeactivatedError, ValueError):
|
|
self._db.set("hikka.inline", "bot_token", None)
|
|
self._token = False
|
|
|
|
if not after_break:
|
|
return await self._register_manager(True)
|
|
|
|
self.init_complete = False
|
|
return False
|
|
except YouBlockedUserError:
|
|
await self._client(UnblockRequest(id=self.bot_username))
|
|
try:
|
|
m = await self._client.send_message(self.bot_username, "/start")
|
|
except Exception:
|
|
logger.critical("Can't unblock users bot", exc_info=True)
|
|
return False
|
|
except Exception:
|
|
self.init_complete = False
|
|
logger.critical("Initialization of inline manager failed!", exc_info=True)
|
|
return False
|
|
|
|
await self._client.delete_messages(self.bot_username, m)
|
|
|
|
# Register required event handlers inside aiogram
|
|
self._dp.register_inline_handler(
|
|
self._inline_handler,
|
|
lambda inline_query: True,
|
|
)
|
|
|
|
self._dp.register_callback_query_handler(
|
|
self._callback_query_handler,
|
|
lambda query: True,
|
|
)
|
|
|
|
self._dp.register_chosen_inline_handler(
|
|
self._chosen_inline_handler,
|
|
lambda chosen_inline_query: True,
|
|
)
|
|
|
|
self._dp.register_message_handler(
|
|
self._message_handler,
|
|
lambda *args: True,
|
|
content_types=["any"],
|
|
)
|
|
|
|
old = self.bot.get_updates
|
|
revoke = self._dp_revoke_token
|
|
|
|
async def new(*args, **kwargs):
|
|
nonlocal revoke, old
|
|
try:
|
|
return await old(*args, **kwargs)
|
|
except TerminatedByOtherGetUpdates:
|
|
await revoke()
|
|
except Unauthorized:
|
|
logger.critical("Got Unauthorized")
|
|
await self._stop()
|
|
|
|
self.bot.get_updates = new
|
|
|
|
# Start polling as the separate task, just in case we will need
|
|
# to force stop this coro. It should be cancelled only by `stop`
|
|
# because it stops the bot from getting updates
|
|
self._task = asyncio.ensure_future(self._dp.start_polling())
|
|
self._cleaner_task = asyncio.ensure_future(self._cleaner())
|
|
|
|
async def _stop(self):
|
|
self._task.cancel()
|
|
self._dp.stop_polling()
|
|
self._cleaner_task.cancel()
|
|
|
|
def pop_web_auth_token(self, token) -> bool:
|
|
"""Check if web confirmation button was pressed"""
|
|
if token not in self._web_auth_tokens:
|
|
return False
|
|
|
|
self._web_auth_tokens.remove(token)
|
|
return True
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise Exception("This file must be called as a module")
|