diff --git a/code/base.py b/code/base.py index 2ade2d6..3e3f0c2 100644 --- a/code/base.py +++ b/code/base.py @@ -1,8 +1,8 @@ # ДАННЫЕ БОТА -TOKEN = "" # @chat_abobot -DEBAG = "-*********" # Технический чат +TOKEN = "XXXXXXXXXX" # @chat_abobot +DEBAG = "XXXXXXXXXX" # Технический чат -TEX_GROUP = "-*********" +TEX_GROUP = "XXXXXXXXXX" # ОБРАЩЕНИЯ К ПОЛЬЗОВАТЕЛЯМ KILL_LIST = ["побить", "отмудохать", "избить", "уебать", "отметелить"] diff --git a/code/bot.py b/code/bot.py index 6598e98..b1c551b 100644 --- a/code/bot.py +++ b/code/bot.py @@ -1,512 +1,20 @@ -import logging, random, pymorphy2, requests -import asyncio, base, re, os, enchant, sql -import speech_recognition as sr -import soundfile as sf - -from gtts import gTTS -from script import checker, translator, notice, lang_form, revers, upd_stat -from aiogram import Bot, Dispatcher, executor, types -from datetime import datetime as dt -# from filters import Admin - -# log level -logging.basicConfig(level=logging.INFO) - -# bot init -bot = Bot(token=base.TOKEN) -dp = Dispatcher(bot) -morph = pymorphy2.MorphAnalyzer() -engl_dict = enchant.Dict("en_US") - -# инициализируем соединение с БД -db = sql.Base('../db/base.db') -du = sql.User('../db/users.db') -dg = sql.Group('../db/groups.db') -dm = sql.Month('../db/month.db') - -# инициализируем фильтры -# dp.filters_factory.bind(Admin) - - -@dp.message_handler(content_types=["new_chat_members"]) -async def notification(message: types.Message): - if not du.group_exists(message.chat.id): - du.add_group(message.chat.id) - - group_id = du.get_group_id(message.chat.id) - db.add_group(group_id) - dg.created_group(group_id) - - await bot.send_message(message.chat.id, f'Привет группа {message.chat.title}!\n\nВсе функции вы можете ' - f'узнать по команде /help! Для того, чтобы ' - f'уведомления по имени и команда /all нормально функционировали, ' - f'необходимо чтобы каждый участник группы написал хотя бы одно ' - f'сообщение в чат! Также для того, чтобы системные сообщения удалялись ' - f'автоматически, необходимо боту выдать права администратора!', - types.ParseMode.HTML) - else: - try: - await message.delete() - except Exception: - return - - -# ОБНОВЛЕНИЕ АЙДИ ГРУППЫ -@dp.message_handler(content_types=['migrate_to_chat_id', 'migrate_from_chat_id']) -async def chat_reload(message: types.Message): - if du.group_exists(message.migrate_from_chat_id): - du.update_group_id(du.get_group_id(message.migrate_from_chat_id), message.migrate_to_chat_id) - - -# КОМАНДЫ -@dp.message_handler(commands=['start', 'help']) -async def helps(message: types.Message): - if message.chat.id > 0: - user_id = message.from_user.id - if not du.user_exists(user_id): - du.add_user(user_id) - else: - group_id, user_id = message.chat.id, message.from_user.id - if not du.user_exists(user_id): - du.add_user(user_id) - if not du.group_exists(group_id): - du.add_group(group_id) - upd_stat(user_id, group_id, 3, message.from_user.first_name, True) - - buttons = [types.InlineKeyboardButton(text="КОМАНДЫ", callback_data="com"), - types.InlineKeyboardButton(text="ИВЕНТЫ", callback_data="even"), - types.InlineKeyboardButton(text="АВТОР", callback_data="auth"), - types.InlineKeyboardButton(text="ФУНКЦИИ", callback_data="fun")] - - keyboard = types.InlineKeyboardMarkup(row_width=2) - keyboard.add(*buttons) - - try: - await bot.send_voice(chat_id=message.chat.id, voice=open('../data/tts.ogg', 'rb'), - caption='*-* Этот АБОБОТ поможет вам приятно провести время в чате с различными командами, ' - 'ивентами и удобными функциями, которые облегчают использование чата)\n\n' - '*-* Также прошу если вам понравился бот, оставить отзыв о его использовании на ' - 'команду /report)', parse_mode=types.ParseMode.MARKDOWN, reply_markup=keyboard) - except Exception: - await bot.send_message(chat_id=message.chat.id, - text='*-* Этот АБОБОТ поможет вам приятно провести время в чате с различными командами, ' - 'ивентами и удобными функциями, которые облегчают использование чата)\n\n' - '*-* Также прошу если вам понравился бот, оставить отзыв о его использовании на ' - 'команду /report)', parse_mode=types.ParseMode.MARKDOWN, reply_markup=keyboard) - - -# ИЛАЙН КЛАВИАТУРА HELP -@dp.callback_query_handler(text="auth") -async def author(call: types.CallbackQuery): - await call.message.answer(text='*| АВТОР |*\n\n*>>* Этот бот, как бы это не печально звучало, но одна из лучших' - ' моих работ и если кого-нибудь у меня получится действительно достойный продукт,' - ' вы сможете о нём узнать в моём телеграм канале *@programium*', parse_mode=types.ParseMode.MARKDOWN) - - -@dp.callback_query_handler(text="fun") -async def function(call: types.CallbackQuery): - await call.message.answer(text='*| ФУНКЦИИ |*\n\n*1.* Возможность перевода случайно написанного текста на ' - 'транслите\n*2.* Ведение обширной статистики сообщений\n*3.* Упоминание участника ' - 'при написании его имени в чате\n*4.* Автоматическое удаление системных сообщений', - parse_mode=types.ParseMode.MARKDOWN) - - -@dp.callback_query_handler(text="com") -async def commands(call: types.CallbackQuery): - await call.message.answer(text='| КОМАНДЫ |\n\n/all - упомянуть всех в чате\n/help - полный список функций\n' - '/recognize - транскрипция отмеченного голосового сообщения в текст\n' - '/stat_group - полная статистика группы\n/stat_user - полная статистика ' - 'отправителя\n/edit и /back_edit - первая команда даёт возможность ' - 'сменить имя для упоминаний на любое слово, а вторая для возврата динамического ' - 'имени\n/start_bot и /stop_bot - возможность отключения текстовых ивентов', - parse_mode=types.ParseMode.HTML) - - -@dp.callback_query_handler(text="even") -async def events(call: types.CallbackQuery): - await call.message.answer(text='*| ИВЕНТЫ |*\n\n*"Чмокнуть"* - сделать кому-нибудь приятно\n*"Отмудохать"* - ' - 'выместить злость на кого-нибудь\n*"Число от ... до ..."* - случайное значение из ' - 'диапозона\n*"Подраться с ..."* - повод кого-нибудь побить\n*"Переведи (..) - ..."* ' - '- перевод слова на керпичный язык\n*"Дай блять совет!"* - даёт рандомный охуенный ' - 'совет\n*"Переверни - ..."* - переворачивает слова в предложении\n*"Озвучь - ..."* ' - '- озвучивает написанный текст', - parse_mode=types.ParseMode.MARKDOWN) - - -# ОСТАЛЬНЫЕ КОМАНДЫ -@dp.message_handler(commands=['all'], commands_prefix='@/') -async def every(message: types.Message): - if message.chat.id < 0: - upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True) - try: - await message.reply(notice(du.get_user_id(message.from_user.id), True, du.get_group_id(message.chat.id), message.from_user.id), - types.ParseMode.HTML) - except Exception as e: - # print(repr(e)) - await message.reply('В группе состоит менее 3х человек, из-за чего команда не работает!') - else: - await message.reply('Эта команда предназначена для вызова в чате!') - - -@dp.message_handler(commands=["recognize"]) -async def recognise(message: types.Message): - user_id = du.get_user_id(message.from_user.id) - - if "reply_to_message" in message: - if "voice" in message.reply_to_message: - - num = random.randint(1000, 9999) - audio = f"../data/voices/{user_id}_{num}.oga" - - file_id = message.reply_to_message.voice.file_id - file = await bot.get_file(file_id) - file_path = file.file_path - await bot.download_file(file_path, audio) - - data, samplerate = sf.read(audio) - os.remove(audio) - audio = f"../data/voices/{user_id}_{num}.wav" - sf.write(audio, data, samplerate) - - af = sr.AudioFile(audio) - r = sr.Recognizer() - with af as source: - r.pause_threshold = 100 - source = r.listen(source) - - try: - mes = await bot.send_message(chat_id=message.chat.id, text=f"Распознавание.....", - parse_mode=types.ParseMode.MARKDOWN, reply_to_message_id=message.reply_to_message.message_id) - try: - query = r.recognize_google(source, language='ru-RU') - os.remove(audio) - await mes.edit_text(f'*{message.reply_to_message.from_user.first_name} сказал(a)* "{query}"', types.ParseMode.MARKDOWN) - except Exception as e: - try: os.remove(audio) - except Exception as e: pass - - await mes.edit_text("Распознать сообщение не удалось!", types.ParseMode.MARKDOWN) - except Exception as e: - print(repr(e)) - pass - return - - -@dp.message_handler(commands=['stat_group']) -async def stat_group(message: types.Message): - if message.chat.id < 0: - upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True) - group_id = du.get_group_id(message.chat.id) - - group = db.stat_group(group_id) - month = db.month_stat_group(group_id) - - await message.answer(text=f'*| СТАТИСТИКА ГРУППЫ |*\n\n' - f'*>>* В целом сообщений *[ {message.message_id} ]*\n\n' - f'*- За всё время* / *За месяц -*\n' - f'*>>* Сообщений в базе *[ {group[0]} / {month[0]} ]*\n\n' - f'*>* Ответов *- [ {group[1]} / {month[1]} ]*\n' - f'*>* Команд *- [ {group[2]} / {month[2]} ]*\n' - f'*>* Ссылок *- [ {group[3]} / {month[3]} ]*\n' - f'*>* Стикеров *- [ {group[5]} / {month[5]} ]*\n' - f'*>* Медиа файлов *- [ {group[4]} / {month[4] } ]*\n' - f'*>* Голос/Кружочки *- [ {group[6]} / {month[6]} ]*', - parse_mode=types.ParseMode.MARKDOWN) - - -@dp.message_handler(commands=['stat_user']) -async def stat_user(message: types.Message): - if message.chat.id < 0: - upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True) - user_id, group_id = du.get_user_id(message.from_user.id), du.get_group_id(message.chat.id) - - group = dg.stat_user(user_id, group_id) - month = dm.stat_user(user_id, group_id) - - namer = "".join(re.sub(r'[^\w\s]', '', message.from_user.first_name).split()) - name = morph.parse(namer)[0].inflect({"gent"}) - - if name is None: name = namer - else: name = name.word - - await message.answer(text=f'*| СТАТИСТИКА {name.upper()} |*\n\n' - f'*- За всё время* / *За месяц -*\n' - f'*>>* Сообщений в базе *[ {group[0]} / {month[0]} ]*\n\n' - f'*>* Ответов *- [ {group[1]} / {month[1]} ]*\n' - f'*>* Команд *- [ {group[2]} / {month[2]} ]*\n' - f'*>* Ссылок *- [ {group[3]} / {month[3]} ]*\n' - f'*>* Стикеров *- [ {group[5]} / {month[5]} ]*\n' - f'*>* Медиа файлов *- [ {group[4]} / {month[4]} ]*\n' - f'*>* Голос/Кружочки *- [ {group[6]} / {month[6]} ]*', - parse_mode=types.ParseMode.MARKDOWN) - - -@dp.message_handler(commands=['edit']) -async def update(message: types.Message): - if message.chat.id < 0: - upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True) - user_id, group_id = du.get_user_id(message.from_user.id), du.get_group_id(message.chat.id) - - text_edit = re.sub(r'[^\w\s]', '', message.text.lower()).split() - if len(text_edit) == 2: - name = morph.parse(text_edit[1])[0] - - if name is None: name = text_edit[1] - else: name = name.normal_form - - if name not in list(map(lambda x: x[0], dg.all_names(group_id))): - if not db.edit_user_exists(user_id): - db.add_edit_user(user_id) - - dg.update_name(user_id, group_id, name) - await message.reply(f'{name.title()}, ваше имя было успешно изменено)') - else: - await message.reply(f'{message.from_user.first_name.lower().title()}, такое имя уже присутствует в чате!') - else: - await message.reply('Вы не правильно ввели имя! Имя должно быть ' - 'из одного слова и идти сразу после команды!') - - -@dp.message_handler(commands=['back_edit']) -async def update_return(message: types.Message): - if message.chat.id < 0: - upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True) - user_id, group_id = du.get_user_id(message.from_user.id), du.get_group_id(message.chat.id) - name = re.sub(r'[^\w\s]', '', message.from_user.first_name.lower()) - - if db.edit_user_exists(user_id): - db.del_edit_user(user_id) - dg.update_name(user_id, group_id, name) - - await message.reply(f'{name.title()}, вы успешно вернулись к динамическому изменению имени)') - else: - await message.reply(f'{name.title()}, вы не устанавливали постоянное имя!') - - -@dp.message_handler(commands=['start_bot']) -async def opening(message: types.Message): - if message.chat.id < 0: - upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True) - - group_id = du.get_group_id(message.chat.id) - if db.check_status(group_id): - await message.answer("У вас уже включены текстовые ивенты!") - else: - db.update_status(group_id) - await message.answer("Текстовые ивенты включены!") - - -@dp.message_handler(commands=['stop_bot']) -async def closing(message: types.Message): - if message.chat.id < 0: - upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True) - - group_id = du.get_group_id(message.chat.id) - if db.check_status(group_id): - db.update_status(group_id) - await message.answer("Текстовые ивенты отключены!") - else: - await message.answer("У вас уже отключены текстовые ивенты!") - - -# УДАЛЕНИЕ ПОЛЬЗОВАТЕЛЕЙ АВТОМАТИЧЕСКИ -@dp.message_handler(content_types=["left_chat_member"]) -async def delete(message: types.Message): - if du.user_exists(message.left_chat_member.id): - user_id, group_id = du.get_user_id(message.left_chat_member.id), du.get_group_id(message.chat.id) - - dg.del_user(group_id, user_id) - if db.group_exists_month(group_id): - if dm.user_exists(user_id, group_id): dm.del_user(group_id, user_id) - - try: await message.delete() - except Exception: return - - -# УДАЛЕНИЕ ТЕХ. СООБЩЕНИЙ -@dp.message_handler(content_types=["new_chat_title", "new_chat_photo", "pinned_message", "voice_chat_ended", - "voice_chat_participants_invited"]) -async def chat_events(message: types.Message): - try: await message.delete() - except Exception: return - - -# СТАТИСТИКА -@dp.message_handler(content_types=['location', 'contact', 'video', 'photo', 'audio', 'document']) -async def media(message: types.Message): - if message.chat.id < 0: upd_stat(message.from_user.id, message.chat.id, 5, message.from_user.first_name, True) - - -@dp.message_handler(content_types=['voice', 'video_note']) -async def voice(message: types.Message): - if message.chat.id < 0: upd_stat(message.from_user.id, message.chat.id, 7, message.from_user.first_name, True) - - if "voice" in message and message.chat.id < 0: - if message.voice.duration <= 60: - user_id = du.get_user_id(message.from_user.id) - - num = random.randint(1000, 9999) - audio = f"../data/voices/{user_id}_{num}.oga" - - file_id = message.voice.file_id - file = await bot.get_file(file_id) - file_path = file.file_path - await bot.download_file(file_path, audio) - - data, samplerate = sf.read(audio) - os.remove(audio) - audio = f"../data/voices/{user_id}_{num}.wav" - sf.write(audio, data, samplerate) - - af = sr.AudioFile(audio) - r = sr.Recognizer() - with af as source: - r.pause_threshold = 100 - source = r.listen(source) - - try: - query = r.recognize_google(source, language='ru-RU') - os.remove(audio) - - # ПЕРЕМЕННЫЕ - group_id = message.chat.id - unsigned = re.sub(r'[^\w\s]', '', query.lower()).split() # СПИСОК СЛОВ БЕЗ ПУНКТУАЦИИ - first_form = [morph.parse(i)[0].normal_form for i in unsigned] # СПИСОК СЛОВ В ПЕРВОЙ ФОРМЕ - names = [_ for _ in first_form if _ in list(map(lambda x: x[0], dg.all_names(du.get_group_id(group_id))))] - - if names: - await message.reply(notice(names, False, du.get_group_id(group_id), message.from_user.id), types.ParseMode.HTML) - return - - except Exception as e: - try: os.remove(audio) - except Exception as e: pass - - return - - -@dp.message_handler(content_types=['sticker']) -async def stick(message: types.Message): - if message.chat.id < 0: upd_stat(message.from_user.id, message.chat.id, 6, message.from_user.first_name, True) - - -# ТЕКСТОВЫЕ ИВЕНТЫ -@dp.message_handler(content_types=['text']) -async def send_events(message: types.Message): - group_id, user_id, name = message.chat.id, message.from_user.id, message.from_user.first_name - - # ОБНОВЛЕНИЕ КОЛ-ВО - if message.chat.id < 0: - upd_stat(user_id, group_id, 1, name) # СООБЩЕНИЙ - if len(message.text) > 1 and message.text[0] == '/': upd_stat(user_id, group_id, 3, name) # КОМАНД - if 'reply_to_message' in message: upd_stat(user_id, group_id, 2, name) # ОТВЕТОВ НА СООБЩЕНИЯ - - # ПЕРЕМЕННЫЕ - low_mes = message.text.lower() # СООБЩЕНИЕ В НИЖНЕМ РЕГИСТРЕ - words = message.text.split() # СПИСОК СЛОВ В СООБЩЕНИИ - unsigned = re.sub(r'[^\w\s]', '', low_mes).split() # СПИСОК СЛОВ БЕЗ ПУНКТУАЦИИ - first_form = [morph.parse(i)[0].normal_form for i in unsigned] # СПИСОК СЛОВ В ПЕРВОЙ ФОРМЕ - if message.chat.id < 0: # СПИСОК ИМЕН В СООБЩЕНИИ (ТОЛЬКО В ГРУППЕ) - names = [_ for _ in first_form if _ in list(map(lambda x: x[0], dg.all_names(du.get_group_id(group_id))))] - - if len(words) >= 2: - # ПОЛЕЗНЫЕ ФУНКЦИИ - if len(words) == 5 and "число от" in low_mes: - await message.answer( - text=f"Число [ {random.randint(int(low_mes.split()[2]), int(low_mes.split()[4]))} ]", - parse_mode=types.ParseMode.HTML) - return - - if unsigned[0] == 'переведи': - if "переведи - " in low_mes: - await message.answer(lang_form([words[_] for _ in range(len(words)) if _ > 1])) - elif f"переведи ({unsigned[1]}) - " in low_mes: - if len(unsigned[1]) == 1: - await message.answer(lang_form([words[_] for _ in range(len(words)) if _ > 2], unsigned[1])) - return - - if unsigned[0] == 'переверни': - if "переверни - " in low_mes: - await message.answer(revers(message.text[12:], True)) - elif "переверни полностью - " in low_mes: - await message.answer(revers(message.text[22:], False)) - return - - if unsigned[0] == 'озвучь' and "озвучь - " in low_mes: - text_to_voice = message.text[9:] - tts = gTTS(text_to_voice, lang='ru') - tts.save('../data/voices/voice.ogg') - await bot.send_voice(chat_id=group_id, voice=open('../data/voices/voice.ogg', 'rb'), - caption=f"{text_to_voice}", parse_mode=types.ParseMode.HTML) - os.remove('../data/voices/voice.ogg') - return - - # РАНДОМ ИВЕНТЫ - if "подраться" == words[0].lower() and "с" == words[1].lower(): - text = " ".join([words[i] for i in range(len(words)) if i > 1]) - - if random.randint(0, 1) == 0: - await message.bot.send_photo(chat_id=group_id, - photo=open(f"../data/fight/({random.randint(1, 8)}).jpg", 'rb'), - caption=f"{message.from_user.first_name}, ты был унижен {text.title()}" - f", с помощью {base.VAR_LOSE[random.randint(0, 3)]}") - else: - await message.bot.send_photo(chat_id=group_id, - photo=open(f"../data/fight/({random.randint(1, 8)}).jpg", 'rb'), - caption=f"{message.from_user.first_name}, ты победил в драке " - f"с {text.title()}, {base.VAR_WIN[random.randint(0, 1)]}") - - # ИВЕНТ ВЗАИМОДЕЙСТВИЯ - for word in base.TMOK_LIST: - if word in low_mes: - lst = [words[i] for i in range(len(words)) if i != 0] - text = " ".join(lst) - - slv = morph.parse(words[0].lower())[0] - await message.bot.send_photo(chat_id=group_id, - photo=open(f"../data/tmok/({random.randint(1, 4)}).jpg", 'rb'), - caption=f"{message.from_user.first_name} " - f"{slv.inflect({'past', 'sing', 'indc'}).word} {text}") - - for word in base.KILL_LIST: - if word in low_mes: - lst = [words[i] for i in range(len(words)) if i != 0] - text = " ".join(lst) - - slv = morph.parse(words[0].lower())[0] - await message.bot.send_photo(chat_id=group_id, - photo=open(f"../data/kill/({random.randint(1, 6)}).jpg", 'rb'), - caption=f"{message.from_user.first_name} " - f"{slv.inflect({'past', 'sing', 'indc'}).word} {text}") - - if unsigned[0] in base.QUAT_LIST[0] and \ - unsigned[1] in base.QUAT_LIST[1] and unsigned[2] in base.QUAT_LIST[2]: - word = requests.get('http://fucking-great-advice.ru/api/random').json() - await message.reply(word["text"]) - return - - if message.chat.id < 0: - # ЛИСТ КОМАНДЫ - if names: - try: - await message.reply(notice(names, False, du.get_group_id(group_id), user_id), types.ParseMode.HTML) - except Exception as e: - pass - """ - await bot.send_message(chat_id=base.TEX_GROUP, text=f"[ {str(dt.now())[:-10]} ] " - f"=> {repr(e)} (уведомления по именам)", - parse_mode=types.ParseMode.HTML) - """ - return - - # ПЕРЕВОДЧИК СЛОВ - if checker([i for i in low_mes], words, group_id, user_id, name.lower()) == len(low_mes) and \ - not any([engl_dict.check(i) for i in unsigned if len(i) > 1]): - await message.reply(f"[{message.from_user.first_name}](tg://user_id?id={user_id}) *>* {translator(words)}", - types.ParseMode.MARKDOWN) - return - - -if __name__ == '__main__': - loop = asyncio.get_event_loop() - executor.start_polling(dp, skip_updates=True) +import asyncio +import logging + +from init import bot, dp +from handlers import router + + +async def main() -> None: + dp.include_router(router) + await bot.delete_webhook(drop_pending_updates=True) + await dp.start_polling(bot, allowed_updates=dp.resolve_used_update_types(), skip_updates=True) + + +if __name__ == '__main__': + logging.basicConfig(level=logging.INFO) + + try: asyncio.run(main()) + except KeyboardInterrupt: + print("Бот остановлен") + pass \ No newline at end of file diff --git a/code/handlers.py b/code/handlers.py new file mode 100644 index 0000000..450e06e --- /dev/null +++ b/code/handlers.py @@ -0,0 +1,540 @@ +from aiogram import F, Router +from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton, FSInputFile +from aiogram.filters import Command, CommandStart +from aiogram.enums import ContentType + +import logging, random, requests, os, re +import speech_recognition as sr +import soundfile as sf +from gtts import gTTS + +from init import * +from script import * +import base + +router = Router() + +# НОВЫЕ УЧАСТНИКИ ГРУППЫ +@router.message(F.content_type == ContentType.NEW_CHAT_MEMBERS) +async def notification(message: Message): + if not du.group_exists(message.chat.id): + du.add_group(message.chat.id) + + group_id = du.get_group_id(message.chat.id) + db.add_group(group_id) + dg.created_group(group_id) + + await bot.send_message( + message.chat.id, + f'*Привет группа {message.chat.title}!*\n\n' + f'Все функции вы можете узнать по команде /help! Для того, чтобы ' + f'уведомления по имени и команда /all нормально функционировали, ' + f'необходимо чтобы каждый участник группы написал хотя бы одно ' + f'сообщение в чат! Также для того, чтобы системные сообщения удалялись ' + f'автоматически, необходимо боту выдать права администратора!' + ) + else: + try: + await message.delete() + except Exception: + return + +# ОБНОВЛЕНИЕ АЙДИ ГРУППЫ +@router.message(F.content_type.in_([ContentType.MIGRATE_TO_CHAT_ID, ContentType.MIGRATE_FROM_CHAT_ID])) +async def chat_reload(message: Message): + if du.group_exists(message.migrate_from_chat_id): + du.update_group_id(du.get_group_id(message.migrate_from_chat_id), message.migrate_to_chat_id) + +# КОМАНДЫ HELP И START +@router.message(CommandStart()) +@router.message(Command('help')) +async def helps(message: Message): + if message.chat.id > 0: + user_id = message.from_user.id + if not du.user_exists(user_id): + du.add_user(user_id) + else: + group_id, user_id = message.chat.id, message.from_user.id + if not du.user_exists(user_id): + du.add_user(user_id) + if not du.group_exists(group_id): + du.add_group(group_id) + upd_stat(user_id, group_id, 3, message.from_user.first_name, True) + + buttons = [ + [InlineKeyboardButton(text="КОМАНДЫ", callback_data="com"), + InlineKeyboardButton(text="ИВЕНТЫ", callback_data="even")], + [InlineKeyboardButton(text="АВТОР", callback_data="auth"), + InlineKeyboardButton(text="ФУНКЦИИ", callback_data="fun")] + ] + + keyboard = InlineKeyboardMarkup(inline_keyboard=buttons) + + try: + await bot.send_voice( + chat_id=message.chat.id, + voice=FSInputFile('../data/tts.ogg'), + caption='*-* Этот АБОБОТ поможет вам приятно провести время в чате с различными командами, ' + 'ивентами и удобными функциями, которые облегчают использование чата)\n\n' + '*-* Также прошу если вам понравился бот, оставить отзыв о его использовании на ' + 'команду /report)', + reply_markup=keyboard + ) + except Exception: + await bot.send_message( + chat_id=message.chat.id, + text='*-* Этот АБОБОТ поможет вам приятно провести время в чате с различными командами, ' + 'ивентами и удобными функциями, которые облегчают использование чата)\n\n' + '*-* Также прошу если вам понравился бот, оставить отзыв о его использовании на ' + 'команду /report)', + reply_markup=keyboard + ) + +# INLINE КЛАВИАТУРА ОБРАБОТЧИКИ +@router.callback_query(F.data == "auth") +async def author(call: CallbackQuery): + await call.message.answer( + text='*| АВТОР |*\n\n*>>* Этот бот, как бы это не печально звучало, но одна из лучших' + ' моих работ и если кого-нибудь у меня получится действительно достойный продукт,' + ' вы сможете о нём узнать в моём телеграм канале *@programium*' + ) + +@router.callback_query(F.data == "fun") +async def function(call: CallbackQuery): + await call.message.answer( + text='*| ФУНКЦИИ |*\n\n*1.* Возможность перевода случайно написанного текста на ' + 'транслите\n*2.* Ведение обширной статистики сообщений\n*3.* Упоминание участника ' + 'при написании его имени в чате\n*4.* Автоматическое удаление системных сообщений' + ) + +@router.callback_query(F.data == "com") +async def commands(call: CallbackQuery): + await call.message.answer( + text='*| КОМАНДЫ |*\n\n*/all* - упомянуть всех в чате\n*/help* - полный список функций\n' + '*/recognize* - транскрипция отмеченного голосового сообщения в текст\n' + '*/stat_group* - полная статистика группы\n*/stat_user* - полная статистика ' + 'отправителя\n*/edit и /back_edit* - первая команда даёт возможность ' + 'сменить имя для упоминаний на любое слово, а вторая для возврата динамического ' + 'имени\n*/start_bot и /stop_bot* - возможность отключения текстовых ивентов' + ) + +@router.callback_query(F.data == "even") +async def events(call: CallbackQuery): + await call.message.answer( + text='*| ИВЕНТЫ |*\n\n*"Чмокнуть"* - сделать кому-нибудь приятно\n*"Отмудохать"* - ' + 'выместить злость на кого-нибудь\n*"Число от ... до ..."* - случайное значение из ' + 'диапозона\n*"Подраться с ..."* - повод кого-нибудь побить\n*"Переведи (..) - ..."* ' + '- перевод слова на керпичный язык\n*"Дай блять совет!"* - даёт рандомный охуенный ' + 'совет\n*"Переверни - ..."* - переворачивает слова в предложении\n*"Озвучь - ..."* ' + '- озвучивает написанный текст' + ) + +# КОМАНДА ALL +@router.message(Command('all')) +async def every(message: Message): + if message.chat.id < 0: + upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True) + try: + await message.reply( + notice(du.get_user_id(message.from_user.id), True, + du.get_group_id(message.chat.id), message.from_user.id) + ) + except Exception: + await message.reply('В группе состоит менее 3х человек, из-за чего команда не работает!') + else: + await message.reply('Эта команда предназначена для вызова в чате!') + +# КОМАНДА RECOGNIZE +@router.message(Command("recognize")) +async def recognise(message: Message): + user_id = du.get_user_id(message.from_user.id) + + if message.reply_to_message and message.reply_to_message.voice: + num = random.randint(1000, 9999) + audio = f"../data/voices/{user_id}_{num}.oga" + + file_id = message.reply_to_message.voice.file_id + file = await bot.get_file(file_id) + file_path = file.file_path + await bot.download_file(file_path, audio) + + data, samplerate = sf.read(audio) + os.remove(audio) + audio = f"../data/voices/{user_id}_{num}.wav" + sf.write(audio, data, samplerate) + + af = sr.AudioFile(audio) + r = sr.Recognizer() + with af as source: + r.pause_threshold = 100 + source = r.listen(source) + + try: + mes = await bot.send_message( + chat_id=message.chat.id, + text="Распознавание.....", + reply_to_message_id=message.reply_to_message.message_id + ) + try: + query = r.recognize_google(source, language='ru-RU') + os.remove(audio) + await mes.edit_text(f'*{message.reply_to_message.from_user.first_name} сказал(a)* "{query}"') + except Exception: + try: + os.remove(audio) + except Exception: + pass + await mes.edit_text("Распознать сообщение не удалось!") + except Exception as e: + print(repr(e)) + pass + +# СТАТИСТИКА ГРУППЫ +@router.message(Command('stat_group')) +async def stat_group(message: Message): + if message.chat.id < 0: + upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True) + group_id = du.get_group_id(message.chat.id) + + group = db.stat_group(group_id) + month = db.month_stat_group(group_id) + + await message.answer( + text=f'*| СТАТИСТИКА ГРУППЫ |*\n\n' + f'*>>* В целом сообщений *[ {message.message_id} ]*\n\n' + f'*- За всё время* / *За месяц -*\n' + f'*>>* Сообщений в базе *[ {group[0]} / {month[0]} ]*\n\n' + f'*>* Ответов *- [ {group[1]} / {month[1]} ]*\n' + f'*>* Команд *- [ {group[2]} / {month[2]} ]*\n' + f'*>* Ссылок *- [ {group[3]} / {month[3]} ]*\n' + f'*>* Стикеров *- [ {group[5]} / {month[5]} ]*\n' + f'*>* Медиа файлов *- [ {group[4]} / {month[4]} ]*\n' + f'*>* Голос/Кружочки *- [ {group[6]} / {month[6]} ]*' + ) + +# СТАТИСТИКА ПОЛЬЗОВАТЕЛЯ +@router.message(Command('stat_user')) +async def stat_user(message: Message): + if message.chat.id < 0: + upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True) + user_id, group_id = du.get_user_id(message.from_user.id), du.get_group_id(message.chat.id) + + group = dg.stat_user(user_id, group_id) + month = dm.stat_user(user_id, group_id) + + namer = "".join(re.sub(r'[^\w\s]', '', message.from_user.first_name).split()) + name = morph.parse(namer)[0].inflect({"gent"}) + + if name is None: + name = namer + else: + name = name.word + + await message.answer( + text=f'*| СТАТИСТИКА {name.upper()} |*\n\n' + f'*- За всё время* / *За месяц -*\n' + f'*>>* Сообщений в базе *[ {group[0]} / {month[0]} ]*\n\n' + f'*>* Ответов *- [ {group[1]} / {month[1]} ]*\n' + f'*>* Команд *- [ {group[2]} / {month[2]} ]*\n' + f'*>* Ссылок *- [ {group[3]} / {month[3]} ]*\n' + f'*>* Стикеров *- [ {group[5]} / {month[5]} ]*\n' + f'*>* Медиа файлов *- [ {group[4]} / {month[4]} ]*\n' + f'*>* Голос/Кружочки *- [ {group[6]} / {month[6]} ]*' + ) + +# РЕДАКТИРОВАНИЕ ИМЕНИ +@router.message(Command('edit')) +async def update(message: Message): + if message.chat.id < 0: + upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True) + user_id, group_id = du.get_user_id(message.from_user.id), du.get_group_id(message.chat.id) + + text_edit = re.sub(r'[^\w\s]', '', message.text.lower()).split() + if len(text_edit) == 2: + name = morph.parse(text_edit[1])[0] + + if name is None: + name = text_edit[1] + else: + name = name.normal_form + + if name not in list(map(lambda x: x[0], dg.all_names(group_id))): + if not db.edit_user_exists(user_id): + db.add_edit_user(user_id) + + dg.update_name(user_id, group_id, name) + await message.reply(f'{name.title()}, ваше имя было успешно изменено)') + else: + await message.reply(f'{message.from_user.first_name.lower().title()}, такое имя уже присутствует в чате!') + else: + await message.reply('Вы не правильно ввели имя! Имя должно быть ' + 'из одного слова и идти сразу после команды!') + +# ВОЗВРАТ К ДИНАМИЧЕСКОМУ ИМЕНИ +@router.message(Command('back_edit')) +async def update_return(message: Message): + if message.chat.id < 0: + upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True) + user_id, group_id = du.get_user_id(message.from_user.id), du.get_group_id(message.chat.id) + name = re.sub(r'[^\w\s]', '', message.from_user.first_name.lower()) + + if db.edit_user_exists(user_id): + db.del_edit_user(user_id) + dg.update_name(user_id, group_id, name) + + await message.reply(f'{name.title()}, вы успешно вернулись к динамическому изменению имени)') + else: + await message.reply(f'{name.title()}, вы не устанавливали постоянное имя!') + +# ВКЛЮЧЕНИЕ ТЕКСТОВЫХ ИВЕНТОВ +@router.message(Command('start_bot')) +async def opening(message: Message): + if message.chat.id < 0: + upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True) + + group_id = du.get_group_id(message.chat.id) + if db.check_status(group_id): + await message.answer("У вас уже включены текстовые ивенты!") + else: + db.update_status(group_id) + await message.answer("Текстовые ивенты включены!") + +# ОТКЛЮЧЕНИЕ ТЕКСТОВЫХ ИВЕНТОВ +@router.message(Command('stop_bot')) +async def closing(message: Message): + if message.chat.id < 0: + upd_stat(message.from_user.id, message.chat.id, 3, message.from_user.first_name, True) + + group_id = du.get_group_id(message.chat.id) + if db.check_status(group_id): + db.update_status(group_id) + await message.answer("Текстовые ивенты отключены!") + else: + await message.answer("У вас уже отключены текстовые ивенты!") + +# УДАЛЕНИЕ ПОЛЬЗОВАТЕЛЕЙ АВТОМАТИЧЕСКИ +@router.message(F.content_type == ContentType.LEFT_CHAT_MEMBER) +async def delete(message: Message): + if du.user_exists(message.left_chat_member.id): + user_id, group_id = du.get_user_id(message.left_chat_member.id), du.get_group_id(message.chat.id) + + dg.del_user(group_id, user_id) + if db.group_exists_month(group_id): + if dm.user_exists(user_id, group_id): + dm.del_user(group_id, user_id) + + try: + await message.delete() + except Exception: + return + +# УДАЛЕНИЕ ТЕХНИЧЕСКИХ СООБЩЕНИЙ +@router.message(F.content_type.in_([ + ContentType.NEW_CHAT_TITLE, + ContentType.NEW_CHAT_PHOTO, + ContentType.PINNED_MESSAGE, + ContentType.VIDEO_CHAT_ENDED, + ContentType.VIDEO_CHAT_PARTICIPANTS_INVITED +])) +async def chat_events(message: Message): + try: + await message.delete() + except Exception: + return + +# МЕДИА ФАЙЛЫ +@router.message(F.content_type.in_([ + ContentType.LOCATION, + ContentType.CONTACT, + ContentType.VIDEO, + ContentType.PHOTO, + ContentType.AUDIO, + ContentType.DOCUMENT +])) +async def media(message: Message): + if message.chat.id < 0: + upd_stat(message.from_user.id, message.chat.id, 5, message.from_user.first_name, True) + +# ГОЛОСОВЫЕ СООБЩЕНИЯ И КРУЖОЧКИ +@router.message(F.content_type.in_([ContentType.VOICE, ContentType.VIDEO_NOTE])) +async def voice(message: Message): + if message.chat.id < 0: + upd_stat(message.from_user.id, message.chat.id, 7, message.from_user.first_name, True) + + if message.voice and message.chat.id < 0: + if message.voice.duration <= 60: + user_id = du.get_user_id(message.from_user.id) + + num = random.randint(1000, 9999) + audio = f"../data/voices/{user_id}_{num}.oga" + + file_id = message.voice.file_id + file = await bot.get_file(file_id) + file_path = file.file_path + await bot.download_file(file_path, audio) + + data, samplerate = sf.read(audio) + os.remove(audio) + audio = f"../data/voices/{user_id}_{num}.wav" + sf.write(audio, data, samplerate) + + af = sr.AudioFile(audio) + r = sr.Recognizer() + with af as source: + r.pause_threshold = 100 + source = r.listen(source) + + try: + query = r.recognize_google(source, language='ru-RU') + os.remove(audio) + + group_id = message.chat.id + unsigned = re.sub(r'[^\w\s]', '', query.lower()).split() + first_form = [morph.parse(i)[0].normal_form for i in unsigned] + names = [_ for _ in first_form if _ in list(map(lambda x: x[0], dg.all_names(du.get_group_id(group_id))))] + + if names: + await message.reply(notice(names, False, du.get_group_id(group_id), message.from_user.id)) + return + + except Exception: + try: + os.remove(audio) + except Exception: + pass + +# СТИКЕРЫ +@router.message(F.content_type == ContentType.STICKER) +async def stick(message: Message): + if message.chat.id < 0: + upd_stat(message.from_user.id, message.chat.id, 6, message.from_user.first_name, True) + +# ТЕКСТОВЫЕ ИВЕНТЫ +@router.message(F.content_type == ContentType.TEXT) +async def send_events(message: Message): + group_id, user_id, name = message.chat.id, message.from_user.id, message.from_user.first_name + + # ОБНОВЛЕНИЕ СТАТИСТИКИ + if message.chat.id < 0: + upd_stat(user_id, group_id, 1, name) # СООБЩЕНИЙ + if len(message.text) > 1 and message.text[0] == '/': + upd_stat(user_id, group_id, 3, name) # КОМАНД + if message.reply_to_message: + upd_stat(user_id, group_id, 2, name) # ОТВЕТОВ НА СООБЩЕНИЯ + + # ПЕРЕМЕННЫЕ + low_mes = message.text.lower() + words = message.text.split() + unsigned = re.sub(r'[^\w\s]', '', low_mes).split() + first_form = [morph.parse(i)[0].normal_form for i in unsigned] + + if message.chat.id < 0: + names = [_ for _ in first_form if _ in list(map(lambda x: x[0], dg.all_names(du.get_group_id(group_id))))] + + if len(words) >= 2: + # ПОЛЕЗНЫЕ ФУНКЦИИ + if len(words) == 5 and "число от" in low_mes: + try: + num1, num2 = int(low_mes.split()[2]), int(low_mes.split()[4]) + await message.answer( + text=f"Число *[ {random.randint(num1, num2)} ]*" + ) + except ValueError: + pass + return + + if unsigned[0] == 'переведи': + if "переведи - " in low_mes: + await message.answer(lang_form([words[_] for _ in range(len(words)) if _ > 1])) + elif f"переведи ({unsigned[1]}) - " in low_mes: + if len(unsigned[1]) == 1: + await message.answer(lang_form([words[_] for _ in range(len(words)) if _ > 2], unsigned[1])) + return + + if unsigned[0] == 'переверни': + if "переверни - " in low_mes: + await message.answer(revers(message.text[12:], True)) + elif "переверни полностью - " in low_mes: + await message.answer(revers(message.text[22:], False)) + return + + if unsigned[0] == 'озвучь' and "озвучь - " in low_mes: + text_to_voice = message.text[9:] + tts = gTTS(text_to_voice, lang='ru') + tts.save('../data/voices/voice.ogg') + await bot.send_voice( + chat_id=group_id, + voice=FSInputFile('../data/voices/voice.ogg'), + caption=f"*{text_to_voice}*" + ) + os.remove('../data/voices/voice.ogg') + return + + # РАНДОМ ИВЕНТЫ + if "подраться" == words[0].lower() and "с" == words[1].lower(): + text = " ".join([words[i] for i in range(len(words)) if i > 1]) + + if random.randint(0, 1) == 0: + await message.answer_photo( + photo=FSInputFile(f"../data/fight/({random.randint(1, 8)}).jpg"), + caption=f"{message.from_user.first_name}, ты был унижен {text.title()}" + f", с помощью {base.VAR_LOSE[random.randint(0, 3)]}" + ) + else: + await message.answer_photo( + photo=FSInputFile(f"../data/fight/({random.randint(1, 8)}).jpg"), + caption=f"{message.from_user.first_name}, ты победил в драке " + f"с {text.title()}, {base.VAR_WIN[random.randint(0, 1)]}" + ) + + # ИВЕНТ ВЗАИМОДЕЙСТВИЯ + for word in base.TMOK_LIST: + if word in low_mes: + lst = [words[i] for i in range(len(words)) if i != 0] + text = " ".join(lst) + + slv = morph.parse(words[0].lower())[0] + await message.answer_photo( + photo=FSInputFile(f"../data/tmok/({random.randint(1, 4)}).jpg"), + caption=f"{message.from_user.first_name} " + f"{slv.inflect({'past', 'sing', 'indc'}).word} {text}" + ) + + for word in base.KILL_LIST: + if word in low_mes: + lst = [words[i] for i in range(len(words)) if i != 0] + text = " ".join(lst) + + slv = morph.parse(words[0].lower())[0] + await message.answer_photo( + photo=FSInputFile(f"../data/kill/({random.randint(1, 6)}).jpg"), + caption=f"{message.from_user.first_name} " + f"{slv.inflect({'past', 'sing', 'indc'}).word} {text}" + ) + + if (unsigned[0] in base.QUAT_LIST[0] and + unsigned[1] in base.QUAT_LIST[1] and + unsigned[2] in base.QUAT_LIST[2]): + try: + word = requests.get('http://fucking-great-advice.ru/api/random').json() + await message.reply(word["text"]) + except: + pass + return + + if message.chat.id < 0: + # УПОМИНАНИЯ ПО ИМЕНАМ + if names: + try: + await message.reply(notice(names, False, du.get_group_id(group_id), user_id)) + except Exception: + pass + return + + # ПЕРЕВОДЧИК СЛОВ + if (checker([i for i in low_mes], words, group_id, user_id, name.lower()) == len(low_mes) and + not any([engl_dict.check(i) for i in unsigned if len(i) > 1])): + await message.reply( + f"[{message.from_user.first_name}](tg://user_id?id={user_id}) *>* {translator(words)}" + ) + return \ No newline at end of file diff --git a/code/init.py b/code/init.py new file mode 100644 index 0000000..849835e --- /dev/null +++ b/code/init.py @@ -0,0 +1,21 @@ +from aiogram import Bot, Dispatcher +from aiogram.enums.parse_mode import ParseMode +from aiogram.fsm.storage.memory import MemoryStorage +from aiogram.client.bot import DefaultBotProperties + + +import base, enchant, pymorphy3 + +bot = Bot(token=base.TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.MARKDOWN)) +dp = Dispatcher(storage=MemoryStorage()) + +morph = pymorphy3.MorphAnalyzer() +engl_dict = enchant.Dict("en_US") + + +import sql + +db = sql.Base('../db/base.db') +du = sql.User('../db/users.db') +dg = sql.Group('../db/groups.db') +dm = sql.Month('../db/month.db') \ No newline at end of file diff --git a/code/script.py b/code/script.py index 9bb2e7f..e90e49f 100644 --- a/code/script.py +++ b/code/script.py @@ -63,8 +63,7 @@ def notice(name, all_users, group_id, author): if all_users: name = dg.user_name(name, group_id) - usr = [""+names[i].title()+"" for i in range(len(names)) - if names[i] != name.lower()] + usr = [f"[{names[i].title()}](tg://user?id={str(ids[i])})" for i in range(len(names)) if names[i] != name.lower()] usr.append(f'{usr[-2]} и {usr[-1]}') del usr[-2], usr[-2] return f'{", ".join(usr)} вас вызывает {name.title()}' @@ -75,13 +74,12 @@ def notice(name, all_users, group_id, author): no_copy.append(i) if len(no_copy) > 1: # ПЕРЕПИСАТЬ КОД ГАВНА КУСОК - usr = [""+_.title()+"" for _ in no_copy - if int(author) != ids[names.index(_)]] + usr = [f"[{_.title()}](tg://user?id={str(ids[names.index(_)])})" for _ in no_copy if int(author) != ids[names.index(_)]] usr.append(f'{usr[-2]} и {usr[-1]}') del usr[-2], usr[-2] return f"{', '.join(usr)} вас упомянули)" else: - usr = ""+no_copy[0].title()+"" + usr = f"[{no_copy[0].title()}](tg://user?id={str(ids[names.index(no_copy[0])])})" return f"{usr}, тебя упомянули)"