This commit is contained in:
bvn13 2024-07-10 14:56:40 +03:00
commit 2ee1722836
13 changed files with 290 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
local.env
**/*.pyc
test/
newsmaker.session
newsmaker.session-journal
newsmaker.session.bup

27
.vscode/launch.json vendored Normal file
View File

@ -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"
}
]
}

13
Dockerfile Normal file
View File

@ -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" ]

0
README.md Normal file
View File

44
docker-compose.yaml Normal file
View File

@ -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

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
aiohttp==3.9.5
telethon==1.36.0

11
src/bot/__init__.py Normal file
View File

@ -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)

124
src/bot/bot.py Normal file
View File

@ -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 "<No Text>"))
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

20
src/main.py Normal file
View File

@ -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()

11
src/settings/__init__.py Normal file
View File

@ -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)

21
src/settings/config.py Normal file
View File

@ -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)

10
src/signin.py Normal file
View File

@ -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!'))

1
version Normal file
View File

@ -0,0 +1 @@
0.1.0