From a8582c60e3bed5b93c989e2963d40130771cf11d Mon Sep 17 00:00:00 2001 From: Igor <50257429+igorechek06@users.noreply.github.com> Date: Sat, 28 Aug 2021 21:10:16 +0900 Subject: 0.0.1 --- .gitignore | 6 + FunnyPineappleBot.sample.service | 18 +++ README.md | 2 +- dependencies | 2 + handlers/__init__.py | 3 + handlers/ananas_only.py | 10 ++ handlers/generate.py | 15 +++ handlers/on_message.py | 19 ++++ main.py | 17 +++ setup.py | 232 +++++++++++++++++++++++++++++++++++++++ shared/__init__.py | 0 shared/commands.py | 7 ++ shared/config.sample.py | 3 + shared/instances.py | 5 + utils/filters.py | 155 ++++++++++++++++++++++++++ 15 files changed, 493 insertions(+), 1 deletion(-) create mode 100644 FunnyPineappleBot.sample.service create mode 100644 dependencies create mode 100644 handlers/__init__.py create mode 100644 handlers/ananas_only.py create mode 100644 handlers/generate.py create mode 100644 handlers/on_message.py create mode 100644 main.py create mode 100644 setup.py create mode 100644 shared/__init__.py create mode 100644 shared/commands.py create mode 100644 shared/config.sample.py create mode 100644 shared/instances.py create mode 100644 utils/filters.py diff --git a/.gitignore b/.gitignore index b6e4761..5e0f237 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,9 @@ dmypy.json # Pyre type checker .pyre/ + +.idea +.vscode + +FunnyPineappleBot.service +config.py \ No newline at end of file diff --git a/FunnyPineappleBot.sample.service b/FunnyPineappleBot.sample.service new file mode 100644 index 0000000..210b267 --- /dev/null +++ b/FunnyPineappleBot.sample.service @@ -0,0 +1,18 @@ +[Unit] +Description=Telegram bot from FunnyPineappleChat +After=syslog.target +After=network.target + +[Service] +Type=simple +User={username} +WorkingDirectory={path} +ExecStart={py_path} main.py -m +KillMode=control-group +KillSignal=15 +SendSIGKILL={send_kill} +RestartSec=5 +Restart=always + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/README.md b/README.md index dccb00d..4514c6a 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -# FunnyPineappleBot \ No newline at end of file +# [FunnyPineappleBot](https://t.me/FunnyPineappleBot) \ No newline at end of file diff --git a/dependencies b/dependencies new file mode 100644 index 0000000..888ef8a --- /dev/null +++ b/dependencies @@ -0,0 +1,2 @@ +aiogram +mc.py diff --git a/handlers/__init__.py b/handlers/__init__.py new file mode 100644 index 0000000..bf57f77 --- /dev/null +++ b/handlers/__init__.py @@ -0,0 +1,3 @@ +from . import ananas_only +from . import on_message +from . import generate diff --git a/handlers/ananas_only.py b/handlers/ananas_only.py new file mode 100644 index 0000000..7426593 --- /dev/null +++ b/handlers/ananas_only.py @@ -0,0 +1,10 @@ +from shared.instances import dp +from aiogram import types as t +from utils import filters as f + + +@dp.my_chat_member_handler(f.user.add_member) +async def pososi(upd: t.ChatMemberUpdated): + if upd.chat.id not in (-1001444484622, -1001197098429): + await upd.bot.send_message(upd.chat.id, 'https://www.youtube.com/watch?v=xdDhmagsXrc') + await upd.chat.leave() diff --git a/handlers/generate.py b/handlers/generate.py new file mode 100644 index 0000000..3902f07 --- /dev/null +++ b/handlers/generate.py @@ -0,0 +1,15 @@ +import mc +from shared.instances import dp +from aiogram import types as t +from utils import filters as f + + +@dp.message_handler(f.message.chance(10), f.message.is_chat) +async def срать_сообщение_с_шансом(msg: t.Message): + await сгенерировать_хуету(msg) + + +@dp.message_handler(f.message.is_chat, commands=['gen']) +async def сгенерировать_хуету(msg: t.Message): + samples = mc.util.load_txt_samples('samples.txt', separator='§') + await msg.answer(mc.StringGenerator(samples=samples).generate_string()) diff --git a/handlers/on_message.py b/handlers/on_message.py new file mode 100644 index 0000000..b9b5499 --- /dev/null +++ b/handlers/on_message.py @@ -0,0 +1,19 @@ +from shared.instances import dp +from aiogram import types as t +from utils import filters as f + + +async def sosalka(msg: t.Message): + '''сосет сообщения''' + text = msg.text or msg.caption + if text.startswith('/'): + return False + with open('samples.txt', 'a+') as file: + file.write(text.replace('§', '').lower() + '§') + return False + + +@dp.message_handler(f.message.is_chat, f.message.has_text, sosalka, content_types=[t.ContentType.ANY]) +async def НАХУЯ_ПРАВДА_Я_НЕ_ЗНАЮ_ЗАЧЕМ_ЭТА_ФУНКЦИЯ_НУЖНА(): + print('NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER NIGGER ') + return 'я могу сюда любую хуйню написать, все равно в фильтре фолз =)))))))))))))))))00' diff --git a/main.py b/main.py new file mode 100644 index 0000000..d9dce7e --- /dev/null +++ b/main.py @@ -0,0 +1,17 @@ +from aiogram import executor, types as t, Dispatcher +from shared.instances import dp, bot +import logging + +logging.basicConfig(level=logging.INFO) + + +async def on_start(dp: Dispatcher): + from shared.commands import commands + for scope, cmd in commands.items(): + await bot.set_my_commands(cmd, scope) + +if __name__ == '__main__': + import handlers + executor.start_polling( + dp, allowed_updates=t.AllowedUpdates.all(), on_startup=on_start + ) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..b59e23f --- /dev/null +++ b/setup.py @@ -0,0 +1,232 @@ +import os +import platform +import shutil +import sys +import traceback +import typing as p + +term = shutil.get_terminal_size() +sep = "=" * term.columns + +venv = False +default = 1 + +if os.name == "nt": + print(f"Setup not supported on {platform.system()}") + exit() + + +def _opt_selector(options: p.Dict[str, p.Any], default: p.Optional[int] = None, pmt: str = "") -> p.Tuple[int, p.Any]: + _options = {} + print("Choose variant") + print(sep) + + num = 1 + for opt in options: + if options[opt] is None: + print() + continue + + d = "*" if default == num else " " + + print(f" {d}{num} - {opt}") + _options[num] = options[opt] + num += 1 + print(sep) + + while True: + opt = input(f"{pmt}-> ") + if opt.isdigit(): + opt = int(opt) + if opt in _options: + return opt, _options[opt] + if opt == "" and default is not None: + return default, _options[default] + + print("Incorrect answer") + pmt = "" + + +def _yes(default: bool = True) -> bool: + while True: + if default: + it = "[Y|n]" + else: + it = "[y|N]" + + i = input(f"{it} -> ") + if i.lower() in ["y", "n"]: + return i.lower() == "y" + if i == "": + return default + + print("Incorrect answer") + + +def _input(prompt: str, default: str = None, required: bool = True) -> str: + if default: + print(f"Default {default}") + while True: + result = input(f"{prompt} -> ") + if not result: + if default: + result = default + break + elif required: + print("Parameter required") + else: + break + + return result + + +def _cmd(cmd: str, show_cmd: bool = True) -> bool: + if show_cmd: + input(f"Press enter for execute {cmd}") + result = os.system(cmd) + return True if result == 0 else False + + +def _clear(): + print() + print('\033c', end="") + + +def _enter(): + input("Press enter, to continue ...") + + +def systemd_unit_generator(): + while True: + username = _input("Your username", os.environ["USER"]) + path = _input("Path to root of project", os.path.dirname(os.path.abspath(__file__))) + py_path = _input("Path to python 3.9", sys.executable) + + print("Send kill (if SIGTERM Timeout)") + send_kill = "off" + if _yes(True): + send_kill = "on" + + with open("FunnyPineappleBot.sample.service", "r") as file: + sample = file.read().format(username=username, path=path, py_path=py_path, send_kill=send_kill) + + _clear() + print( + f"{sep}", + f"{sample}", + f"{sep}", + f"Your username - {username}", + f"Path to root of project - {path}", + f"Path to python 3.9 - {py_path}", + f"Send kill - {send_kill}", + f"{sep}", + "", + "All correct ?", + sep="\n" + ) + if _yes(False): + with open("FunnyPineappleBot.service", "w") as file: + file.write(sample) + _clear() + + print("Link unit from /etc/systemd/system/ ?") + if _yes(): + _cmd("sudo mv ToolKit.service /etc/systemd/system/") + _cmd("sudo ln /etc/systemd/system/ToolKit.service ./ -s") + break + else: + _clear() + print(sep) + _enter() + return True + + +def config_generator(): + try: + import config + except ImportError: + config = object() + while True: + main_token = _input("Main bot token", getattr(config, "main_token", None)) + test_token = _input("Test bot token", getattr(config, "test_token", None)) + + with open("shared/config.sample.py", "r") as file: + sample = file.read().format(main_token=main_token, test_token=test_token) + + print( + f"{sep}", + f"{sample}", + f"{sep}", + "All correct ?", + sep="\n" + ) + + if _yes(False): + with open("shared/config.py", "w") as file: + file.write(sample) + break + else: + _clear() + return True + + +def install_dependencies(): + with open("dependencies", "r") as file: + dependencies = file.read() + print( + "Install this ?", + f"{sep}", + f"{dependencies}", + f"{sep}", + sep="\n" + ) + _cmd("pip install -U -r dependencies", False) + print(f"{sep}\nSuccessfully installed") + _enter() + return True + + +if __name__ == '__main__': + opts = { + "Setup systemd unit": systemd_unit_generator, + "Setup config.py": config_generator, + "Install or Update dependencies": install_dependencies, + "Exit": exit, + } + exit_index = list(opts.keys()).index("Exit") + 1 + default = 1 + pmt = "" + + _clear() + while True: + if default >= exit_index: + default = exit_index + term = shutil.get_terminal_size() + sep = "=" * term.columns + try: + _clear() + num, opt = _opt_selector(opts, default, pmt) + _clear() + res = opt() + _clear() + + if num != default: + default = num + 1 + elif res is True: + default += 1 + + if res is not True: + pmt = f"{res!r} " + if num == default: + default = num + 1 + else: + pmt = "" + + except KeyboardInterrupt: + break + except Exception as e: + pmt = f"An error has occurred ({e.__class__.__name__}:{e.args[0]})" + trc = traceback.format_exc() + print(trc) + _enter() + _clear() diff --git a/shared/__init__.py b/shared/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/shared/commands.py b/shared/commands.py new file mode 100644 index 0000000..ffed9c3 --- /dev/null +++ b/shared/commands.py @@ -0,0 +1,7 @@ +from aiogram.types import BotCommand as cmd, BotCommandScopeAllGroupChats as group + +commands = { + group(): [ + cmd('gen', 'жидко пукнуть') + ] +} diff --git a/shared/config.sample.py b/shared/config.sample.py new file mode 100644 index 0000000..f4a3f09 --- /dev/null +++ b/shared/config.sample.py @@ -0,0 +1,3 @@ +TOKEN = "" +test_token = "{test_token}" +main_token = "{main_token}" diff --git a/shared/instances.py b/shared/instances.py new file mode 100644 index 0000000..7eb883c --- /dev/null +++ b/shared/instances.py @@ -0,0 +1,5 @@ +from aiogram import Bot, Dispatcher +from .config import TOKEN + +bot = Bot(token=TOKEN) +dp = Dispatcher(bot) diff --git a/utils/filters.py b/utils/filters.py new file mode 100644 index 0000000..b6ddec5 --- /dev/null +++ b/utils/filters.py @@ -0,0 +1,155 @@ +import re +import typing as p +from random import random +from aiogram import types as t, filters as f, Bot + +from shared.instances import bot +# from libs.classes import Errors as e +# from libs.objects import Database +# from libs.system import regex as r + +objType = p.Union[t.Message, t.CallbackQuery, t.ChatMemberUpdated] + + +class _helper: + @staticmethod + def get_user_and_chat(obj: objType): + if isinstance(obj, t.Message): + chat = obj.chat + user = obj.from_user + elif isinstance(obj, t.CallbackQuery): + chat = obj.message.chat + user = obj.from_user + elif isinstance(obj, t.ChatMemberUpdated): + chat = obj.chat + user = obj.from_user + else: + raise TypeError() + + return user, chat + + @staticmethod + def has_permission(admin: t.ChatMember, permission: str): + if t.ChatMemberStatus.is_chat_creator(admin.status): + return True + elif t.ChatMemberStatus.is_chat_admin(admin.status): + return getattr(admin, permission) + else: + return False + + +class AdminFilter(f.BoundFilter): + def __init__(self, user_id: int = None): + self._user_id = user_id + + async def check(self, obj: objType): + user, chat = _helper.get_user_and_chat(obj) + + admin = await chat.get_member(self._user_id or user.id) + if t.ChatMemberStatus.is_chat_admin(admin.status): + return True + else: + return False + + +class AliasFilter(f.BoundFilter): + def __init__(self): + pass + + async def check(self, msg: objType) -> bool: + if not isinstance(msg, t.Message): + raise TypeError() + if await message.is_private.check(msg): + return False + chat = Database.get_chat(msg.chat.id) + + if msg.sticker: + aliases = list(chat.settings.sticker_alias.keys()) + text = msg.sticker.file_unique_id + elif msg.text: + aliases = list(chat.settings.text_alias.keys()) + text = msg.text + + for alias in aliases: + pattern = re.compile(r.alias(alias), re.IGNORECASE) + if pattern.match(text): + return True + + return False + + +class message: + is_chat = f.ChatTypeFilter((t.ChatType.GROUP, t.ChatType.SUPERGROUP)) + is_private = f.ChatTypeFilter(t.ChatType.PRIVATE) + is_reply = f.IsReplyFilter(True) + is_alias = AliasFilter() + + @staticmethod + def chance(percent: int): + def filter(msg: t.Message): + return random() <= (percent / 100) + return filter + + @staticmethod + def has_text(msg: t.Message): + if msg.text or msg.caption: + return True + + +class bot: + is_admin = AdminFilter(bot.id) + + @staticmethod + def has_permission(permissions: p.List[str]): + permissions = permissions + + async def filter(obj: objType): + bot = Bot.get_current() + user, chat = _helper.get_user_and_chat(obj) + admin = await chat.get_member(bot.id) + if not _helper.has_permission(admin, permissions): + raise e.BotHasNotPermission() + return True + + return filter + + +class user: + is_admin = AdminFilter() + + @staticmethod + def has_permission(permissions: p.List[str]): + permissions = permissions + + async def filter(obj: objType): + user, chat = _helper.get_user_and_chat(obj) + admin = await chat.get_member(user.id) + if not _helper.has_permission(admin, permissions): + raise e.HasNotPermission() + return True + + return filter + + @staticmethod + def add_member(upd: t.ChatMemberUpdated): + old = upd.old_chat_member + new = upd.new_chat_member + return not t.ChatMemberStatus.is_chat_member(old.status) and t.ChatMemberStatus.is_chat_member(new.status) + + @staticmethod + def removed_member(upd: t.ChatMemberUpdated): + old = upd.old_chat_member + new = upd.new_chat_member + return t.ChatMemberStatus.is_chat_member(old.status) and not t.ChatMemberStatus.is_chat_member(new.status) + + @staticmethod + def promote_admin(upd: t.ChatMemberUpdated): + old = upd.old_chat_member + new = upd.new_chat_member + return not t.ChatMemberStatus.is_chat_admin(old.status) and t.ChatMemberStatus.is_chat_admin(new.status) + + @staticmethod + def restrict_admin(upd: t.ChatMemberUpdated): + old = upd.old_chat_member + new = upd.new_chat_member + return t.ChatMemberStatus.is_chat_admin(old.status) and not t.ChatMemberStatus.is_chat_admin(new.status) -- cgit v1.2.3