176 lines
8.2 KiB
Python
176 lines
8.2 KiB
Python
import asyncio
|
|
from settings import config
|
|
import logging
|
|
import re
|
|
from queue import Queue, Empty
|
|
from telethon import TelegramClient, events
|
|
from bot.message import WeatherTask
|
|
|
|
logger = logging.getLogger(__name__)
|
|
logger.setLevel(logging.INFO)
|
|
|
|
class Bot():
|
|
|
|
def __init__(self,
|
|
session_file: str,
|
|
config_file: str,
|
|
api_id: str,
|
|
api_hash: int,
|
|
owner_id: int) -> None:
|
|
self.__config_file = config_file
|
|
self.__config = None
|
|
self.__me = None
|
|
self.__owner_id = owner_id
|
|
self.__reload()
|
|
self.__bot = TelegramClient(session_file, api_id, api_hash)
|
|
self.__weather_queue = Queue()
|
|
|
|
@self.__bot.on(events.NewMessage(incoming=True, pattern='!whoami'))
|
|
async def onMessageWhoami(event):
|
|
await event.reply("{0}".format(event.chat_id))
|
|
await self.__bot.send_read_acknowledge(event.chat_id, event.message)
|
|
raise events.StopPropagation
|
|
|
|
@self.__bot.on(events.NewMessage(incoming=True, pattern="!config"))
|
|
async def onMessageReload(event):
|
|
self.__reload()
|
|
await event.reply("```\n{0}\n```".format(self.__config.read_as_text()))
|
|
await self.__bot.send_read_acknowledge(event.chat_id, event.message)
|
|
raise events.StopPropagation
|
|
|
|
@self.__bot.on(events.NewMessage(incoming=True, pattern="!reload"))
|
|
async def onMessageReload(event):
|
|
self.__reload()
|
|
await event.reply("Reloaded")
|
|
await self.__bot.send_read_acknowledge(event.chat_id, event.message)
|
|
raise events.StopPropagation
|
|
|
|
@self.__bot.on(events.NewMessage(incoming=True, pattern="!chats"))
|
|
async def onMessageChats(event):
|
|
await self.__send_all_chats_to_owner()
|
|
await self.__bot.send_read_acknowledge(event.chat_id, event.message)
|
|
raise events.StopPropagation
|
|
|
|
@self.__bot.on(events.ChatAction)
|
|
async def onChatAction(event):
|
|
if event.user_left and event.user.id == self.__me:
|
|
await self.__bot.send_message(owner_id, "Я вышел из чата: {0}".format(event.chat_id))
|
|
if event.user_joined and event.user.id == self.__me:
|
|
await self.__bot.send_message(owner_id, "Я вошел в чат: {0}".format(event.chat_id))
|
|
|
|
@self.__bot.on(events.NewMessage(incoming=True))
|
|
async def onNewMessage(event):
|
|
if event.message is None:
|
|
return
|
|
chat_id = event.chat_id
|
|
message = event.message
|
|
logger.info("Received message in chat {0}, id {1}: {2}".format(chat_id, message.id, message.text if not message == None else "<No Text>"))
|
|
await self.__process_message(event, chat_id, message)
|
|
|
|
async def start(self) -> None:
|
|
await self.__bot.start()
|
|
await self.__identity()
|
|
self.__bot.loop.create_task(self.__task_loop())
|
|
await self.__bot.run_until_disconnected()
|
|
|
|
def send_weather(self, task: WeatherTask) -> None:
|
|
self.__weather_queue.put(task)
|
|
|
|
async def __task_loop(self) -> None:
|
|
while True:
|
|
logger.debug("Looking for weather jobs")
|
|
weather_task = None
|
|
try:
|
|
weather_task = self.__weather_queue.get_nowait()
|
|
except Empty:
|
|
pass
|
|
if weather_task is not None:
|
|
await self.__send_weather(weather_task.get_key(), weather_task.get_message())
|
|
await asyncio.sleep(1)
|
|
|
|
async def __send_weather(self, key: str, message: str) -> None:
|
|
dest_chat_id = self.__config.get_weather_destination_chat_id(key)
|
|
if dest_chat_id is not None:
|
|
await self.__bot.send_message(dest_chat_id, message, parse_mode='html')
|
|
|
|
def __reload(self) -> None:
|
|
self.__config = config.Config(filename=self.__config_file)
|
|
|
|
async def __send_all_chats_to_owner(self) -> None:
|
|
text = ""
|
|
async for dialog in self.__bot.iter_dialogs():
|
|
text = text + "{0} - {1}\n".format(dialog.id, dialog.name)
|
|
await self.__bot.send_message(self.__owner_id, text)
|
|
|
|
async def __process_message(self, event, chat_id, message):
|
|
configs = self.__config.get_on_message_for_chat_id(chat_id)
|
|
if configs == None:
|
|
logger.info("(chat_id, msg_id)=({0}, {1}): Config is None".format(chat_id, message.id))
|
|
return
|
|
if not isinstance(configs, list):
|
|
logger.info("(chat_id, msg_id)=({0}, {1}): Config is not list".format(chat_id, message.id))
|
|
return
|
|
i = 0
|
|
for config in configs:
|
|
i = i + 1
|
|
filter = config['filter'] if 'filter' in config else None
|
|
action = config['action'] if 'action' in config else None
|
|
action_type = action['type'] if 'type' in action else None
|
|
if action == None or action_type == None:
|
|
logger.info("(chat_id, msg_id, cfg_id)=({0}, {1}, {2}): Action is bad".format(chat_id, message.id, i))
|
|
continue
|
|
if not filter == None:
|
|
logger.info("(chat_id, msg_id, cfg_id)=({0}, {1}, {2}): Filter is set".format(chat_id, message.id, i))
|
|
if await self.__needs_skip(filter, message):
|
|
logger.info("(chat_id, msg_id, cfg_id)=({0}, {1}, {2}): Skipping".format(chat_id, message.id, i))
|
|
continue
|
|
if action_type == 'forward':
|
|
logger.info("(chat_id, msg_id, cfg_id)=({0}, {1}, {2}): Action type is 'forward'".format(chat_id, message.id, i))
|
|
destination = action['chatId'] if 'chatId' in action else None
|
|
if destination == None:
|
|
logger.info("(chat_id, msg_id, cfg_id)=({0}, {1}, {2}): Destination is None".format(chat_id, message.id, i))
|
|
continue
|
|
await event.forward_to(destination)
|
|
logger.info("(chat_id, msg_id, cfg_id)=({0}, {1}, {2}): Forwarded".format(chat_id, message.id, i))
|
|
|
|
async def __needs_skip(self, filter: dict, message) -> bool:
|
|
filter_type = filter['type'] if 'type' in filter else None
|
|
filter_value = filter['value'] if 'value' in filter else None
|
|
if filter_type == None or filter_value == None:
|
|
logger.info("msg_id={0}: Filter is bad".format(message.id))
|
|
return True
|
|
text = str(message.text)
|
|
if text == None:
|
|
logger.info("msg_id={0}: Text is None".format(message.id))
|
|
if not message.reply_to == None:
|
|
logger.info("msg_id={0}: Reply is present".format(message.id))
|
|
reply = await self.__get_reply(message.chat_id, message)
|
|
return await self.__needs_skip(filter, reply)
|
|
return True
|
|
if filter_type == 'contain':
|
|
logger.info("msg_id={0}: Filter type is 'contain'".format(message.id))
|
|
if text.find(filter_value) == -1:
|
|
logger.info("msg_id={0}: Text '{1}' not found".format(message.id, filter_value))
|
|
if not message.reply_to == None:
|
|
logger.info("msg_id={0}: Reply is present".format(message.id))
|
|
reply = await self.__get_reply(message.chat_id, message)
|
|
return await self.__needs_skip(filter, reply)
|
|
return True
|
|
elif filter_type == 'regexp':
|
|
logger.info("msg_id={0}: Filter type is 'regexp'".format(message.id))
|
|
if not re.match(filter_value, text):
|
|
logger.info("msg_id={0}: Text '{1}' not found".format(message.id, filter_value))
|
|
if not message.reply_to == None:
|
|
logger.info("msg_id={0}: Reply is present".format(message.id))
|
|
reply = await self.__get_reply(message.chat_id, message)
|
|
return await self.__needs_skip(filter, reply)
|
|
return True
|
|
logger.info("msg_id={0}: Message to be processed".format(message.id))
|
|
return False
|
|
|
|
async def __get_reply(self, chat_id, message):
|
|
return await self.__bot.get_messages(chat_id, ids=message.reply_to.reply_to_msg_id)
|
|
|
|
async def __identity(self) -> None:
|
|
me = await self.__bot.get_me()
|
|
self.__me = me.id |