commit 2ee17228362babc7232f1e8b387426404f05a76c Author: bvn13 Date: Wed Jul 10 14:56:40 2024 +0300 squashed diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6bb173a --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +local.env +**/*.pyc +test/ +newsmaker.session +newsmaker.session-journal +newsmaker.session.bup diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..73ea524 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,27 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + + + { + "name": "Python Debugger: main.py", + "type": "debugpy", + "request": "launch", + "program": "src/main.py", + "console": "integratedTerminal", + "envFile": "${workspaceFolder}/local.env" + }, + { + "name": "Python Debugger: signin.py", + "type": "debugpy", + "request": "launch", + "program": "src/signin.py", + "console": "integratedTerminal", + "envFile": "${workspaceFolder}/local.env" + } + ] +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..cff7ba9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM python:3.10 + +RUN apt-get install libpq-dev -y + +ADD requirements.txt requirements.txt + +RUN pip install -r requirements.txt + +ADD src /app + +WORKDIR /app + +ENTRYPOINT [ "python", "./main.py" ] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..2040ec2 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,44 @@ +version: '3.3' + +networks: + jedoist: + external: true + +services: + + bot: + # build: ./ + image: localhost:5001/jedoist:${APP_VERSION} + environment: + - BOT_TOKEN=${BOT_TOKEN} + - VK_CLIENT_ID=${VK_CLIENT_ID} + - VK_SECRET_KEY=${VK_SECRET_KEY} + - BOT_OWNER_ID=258985362 + - DB_HOST=jedoist-db + - DB_NAME=jedoist-db + - DB_USER=${DB_USER} + - DB_PASS=${DB_PASS} + - VOICES_PATH=${VOICES_PATH} + - CONFIG_FILE=/mnt/config.json + restart: always + depends_on: + - bot-db + networks: + - jedoist + volumes: + - ${CONFIG_FILE}:/mnt/config.json + + bot-db: + image: postgres:14 + container_name: jedoist-db + restart: always + environment: + POSTGRES_USER: ${DB_USER} + POSTGRES_PASSWORD: ${DB_PASS} + POSTGRES_DB: jedoist-db + networks: + - jedoist + volumes: + - ${DB_VOLUME}:/var/lib/postgresql/data + ports: + - 5432:5432 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5754427 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +aiohttp==3.9.5 +telethon==1.36.0 \ No newline at end of file diff --git a/src/bot/__init__.py b/src/bot/__init__.py new file mode 100644 index 0000000..07a2c72 --- /dev/null +++ b/src/bot/__init__.py @@ -0,0 +1,11 @@ +import sys +import os + +# Get the current script's directory +current_dir = os.path.dirname(os.path.abspath(__file__)) + +# Get the parent directory by going one level up +parent_dir = os.path.dirname(current_dir) + +# Add the parent directory to sys.path +sys.path.append(parent_dir) \ No newline at end of file diff --git a/src/bot/bot.py b/src/bot/bot.py new file mode 100644 index 0000000..8084a67 --- /dev/null +++ b/src/bot/bot.py @@ -0,0 +1,124 @@ +from settings import config +import logging +import re +from telethon import TelegramClient, events + +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.__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="!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.debug("Received message in chat {0}: {1}".format(chat_id, message.text if not message == None else "")) + await self.__process_message(event, chat_id, message) + + def start(self) -> None: + self.__bot.start() + self.__bot.loop.run_until_complete(self.__identity()) + self.__bot.run_until_disconnected() + + 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: + return + if not isinstance(configs, list): + return + for config in configs: + 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: + return + if not filter == None: + if await self.__needs_skip(filter, message): + return + if action_type == 'forward': + destination = action['chatId'] if 'chatId' in action else None + if destination == None: + return + await event.forward_to(destination) + + 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: + return True + text = str(message.text) + if text == None: + if not message.reply_to == None: + reply = await self.__get_reply(message.chat_id, message) + return await self.__needs_skip(filter, reply) + return True + if filter_type == 'contain': + if text.find(filter_value) == -1: + if not message.reply_to == None: + reply = await self.__get_reply(message.chat_id, message) + return await self.__needs_skip(filter, reply) + return True + elif filter_type == 'regexp': + if not re.match(filter_value, text): + if not message.reply_to == None: + reply = await self.__get_reply(message.chat_id, message) + return await self.__needs_skip(filter, reply) + return True + 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 \ No newline at end of file diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..74df295 --- /dev/null +++ b/src/main.py @@ -0,0 +1,20 @@ +import os +from bot.bot import Bot +import logging + +logging.basicConfig(format="%(asctime)s | %(name)s | %(levelname)s | %(message)s") +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) + +if __name__ == "__main__": + session_file = os.environ['SESSION_FILE'] + api_id = os.environ['TG_APP_ID'] + api_hash = os.environ['TG_APP_HASH'] + owner_id = int(os.environ['TG_OWNER_ID']) + config_file = os.environ['CONFIG_FILE'] + bot = Bot(session_file=session_file, + api_id=api_id, + api_hash=api_hash, + config_file=config_file, + owner_id=owner_id) + bot.start() diff --git a/src/settings/__init__.py b/src/settings/__init__.py new file mode 100644 index 0000000..07a2c72 --- /dev/null +++ b/src/settings/__init__.py @@ -0,0 +1,11 @@ +import sys +import os + +# Get the current script's directory +current_dir = os.path.dirname(os.path.abspath(__file__)) + +# Get the parent directory by going one level up +parent_dir = os.path.dirname(current_dir) + +# Add the parent directory to sys.path +sys.path.append(parent_dir) \ No newline at end of file diff --git a/src/settings/config.py b/src/settings/config.py new file mode 100644 index 0000000..f5c8c49 --- /dev/null +++ b/src/settings/config.py @@ -0,0 +1,21 @@ +import json +from typing import Optional + +class Config(): + + def __init__(self, filename: str) -> None: + self.__filename = filename + self.__config = {} + self.__read() + + def get_on_message_for_chat_id(self, chat_id: int) -> Optional[dict]: + chat_id_str = str(chat_id) + if 'onMessage' in self.__config: + on_message = self.__config['onMessage'] + if chat_id_str in on_message: + return on_message[chat_id_str] + return None + + def __read(self) -> None: + with open(self.__filename, 'r') as f: + self.__config = json.load(f) diff --git a/src/signin.py b/src/signin.py new file mode 100644 index 0000000..7f70e7f --- /dev/null +++ b/src/signin.py @@ -0,0 +1,10 @@ +import os +from telethon import TelegramClient + +# Use your own values from my.telegram.org +api_id = os.environ['TG_APP_ID'] +api_hash = os.environ['TG_APP_HASH'] + +# The first parameter is the .session file name (absolute paths allowed) +with TelegramClient('newsmaker.session', api_id, api_hash) as client: + client.loop.run_until_complete(client.send_message('me', 'Hello, myself!')) \ No newline at end of file diff --git a/version b/version new file mode 100644 index 0000000..6c6aa7c --- /dev/null +++ b/version @@ -0,0 +1 @@ +0.1.0 \ No newline at end of file