import asyncio from datetime import datetime from pathlib import Path from aiogram import Router, types, F from aiogram.filters import Command, StateFilter from aiogram.fsm.context import FSMContext from aiogram.types import FSInputFile from helper_bot.filters.main import ChatTypeFilter from helper_bot.middlewares.blacklist_middleware import BlacklistMiddleware from helper_bot.utils.helper_func import update_user_info, check_user_emoji, send_voice_message from logs.custom_logger import logger from voice_bot.handlers.constants import * from voice_bot.handlers.dependencies import VoiceBotMiddleware, BotDB, Settings from voice_bot.handlers.services import VoiceBotService from voice_bot.handlers.utils import get_last_message_text, validate_voice_message, get_user_emoji_safe from voice_bot.keyboards.keyboards import get_main_keyboard, get_reply_keyboard_for_voice voice_router = Router() # Middleware voice_router.message.middleware(VoiceBotMiddleware()) voice_router.message.middleware(BlacklistMiddleware()) @voice_router.message( ChatTypeFilter(chat_type=["private"]), Command(CMD_RESTART) ) async def restart_function(message: types.Message, state: FSMContext, bot_db: BotDB): await message.forward(chat_id=bot_db.settings['Telegram']['group_for_logs']) await update_user_info(VOICE_BOT_NAME, message) check_user_emoji(message) markup = get_main_keyboard() await message.answer(text='Я перезапущен!', reply_markup=markup) await state.set_state(STATE_START) @voice_router.message( ChatTypeFilter(chat_type=["private"]), Command(CMD_EMOJI) ) async def handle_emoji_message(message: types.Message, state: FSMContext, bot_db: BotDB): await message.forward(chat_id=bot_db.settings['Telegram']['group_for_logs']) user_emoji = check_user_emoji(message) await state.set_state(STATE_START) if user_emoji is not None: await message.answer(f'Твоя эмодзя - {user_emoji}', parse_mode='HTML') @voice_router.message( ChatTypeFilter(chat_type=["private"]), Command(CMD_HELP) ) async def help_function(message: types.Message, state: FSMContext, bot_db: BotDB): await message.forward(chat_id=bot_db.settings['Telegram']['group_for_logs']) await update_user_info(VOICE_BOT_NAME, message) await message.answer( text=HELP_MESSAGE, disable_web_page_preview=not bot_db.settings['Telegram']['preview_link'] ) await state.set_state(STATE_START) @voice_router.message( ChatTypeFilter(chat_type=["private"]), Command(CMD_START) ) async def start(message: types.Message, state: FSMContext, bot_db: BotDB, settings: Settings): await state.set_state(STATE_START) await message.forward(chat_id=settings['Telegram']['group_for_logs']) await update_user_info(VOICE_BOT_NAME, message) user_emoji = get_user_emoji_safe(bot_db, message.from_user.id) # Создаем сервис и отправляем приветственные сообщения voice_service = VoiceBotService(bot_db, settings) await voice_service.send_welcome_messages(message, user_emoji) @voice_router.message( ChatTypeFilter(chat_type=["private"]), Command(CMD_REFRESH) ) async def refresh_listen_function(message: types.Message, state: FSMContext, bot_db: BotDB): await message.forward(chat_id=bot_db.settings['Telegram']['group_for_logs']) await update_user_info(VOICE_BOT_NAME, message) markup = get_main_keyboard() # Очищаем прослушивания через сервис voice_service = VoiceBotService(bot_db, bot_db.settings) voice_service.clear_user_listenings(message.from_user.id) await message.answer( text=LISTENINGS_CLEARED_MESSAGE, disable_web_page_preview=not bot_db.settings['Telegram']['preview_link'], reply_markup=markup ) await state.set_state(STATE_START) @voice_router.message( StateFilter(STATE_START), ChatTypeFilter(chat_type=["private"]), F.text == BTN_SPEAK ) async def standup_write(message: types.Message, state: FSMContext, bot_db: BotDB): await message.forward(chat_id=bot_db.settings['Telegram']['group_for_logs']) markup = types.ReplyKeyboardRemove() await message.answer(text=RECORD_VOICE_MESSAGE, reply_markup=markup) try: message_with_date = get_last_message_text(bot_db) if message_with_date: await message.answer(text=message_with_date, parse_mode="html") except Exception as e: logger.error(f'Не удалось получить дату последнего сообщения - {e}') await state.set_state(STATE_STANDUP_WRITE) @voice_router.message( StateFilter(STATE_STANDUP_WRITE), ChatTypeFilter(chat_type=["private"]), ) async def suggest_voice(message: types.Message, state: FSMContext, bot_db: BotDB): logger.info( f"Вызов функции suggest_voice. Пользователь: {message.from_user.id} Имя автора сообщения: {message.from_user.full_name}" ) await message.forward(chat_id=bot_db.settings['Telegram']['group_for_logs']) markup = get_main_keyboard() if validate_voice_message(message): markup_for_voice = get_reply_keyboard_for_voice() # Отправляем аудио в приватный канал sent_message = await send_voice_message( bot_db.settings['Telegram']['group_for_posts'], message, message.voice.file_id, markup_for_voice ) # Сохраняем в базу инфо о посте bot_db.set_user_id_and_message_id_for_voice_bot(sent_message.message_id, message.from_user.id) # Отправляем юзеру ответ и возвращаем его в меню await message.answer(text=VOICE_SAVED_MESSAGE, reply_markup=markup) await state.set_state(STATE_START) else: await message.forward(chat_id=bot_db.settings['Telegram']['group_for_logs']) await message.answer(text=UNKNOWN_CONTENT_MESSAGE, reply_markup=markup) await state.set_state(STATE_STANDUP_WRITE) @voice_router.message( StateFilter(STATE_START), ChatTypeFilter(chat_type=["private"]), F.text == BTN_LISTEN ) async def standup_listen_audio(message: types.Message, bot_db: BotDB): markup = get_main_keyboard() # Создаем сервис для работы с аудио voice_service = VoiceBotService(bot_db, bot_db.settings) try: # Получаем случайное аудио audio_data = voice_service.get_random_audio(message.from_user.id) if not audio_data: await message.answer(text=NO_AUDIO_MESSAGE, reply_markup=markup) try: message_with_date = get_last_message_text(bot_db) if message_with_date: await message.answer(text=message_with_date, parse_mode="html") except Exception as e: logger.error(f'Не удалось получить последнюю дату {e}') return audio_for_user, date_added, user_emoji = audio_data # Получаем путь к файлу path = Path(f'{VOICE_USERS_DIR}/{audio_for_user}.ogg') voice = FSInputFile(path) # Маркируем сообщение как прослушанное voice_service.mark_audio_as_listened(audio_for_user, message.from_user.id) # Формируем подпись if user_emoji: caption = f'{user_emoji}\nДата записи: {date_added}' else: caption = f'Дата записи: {date_added}' await message.bot.send_voice( chat_id=message.chat.id, voice=voice, caption=caption, reply_markup=markup ) # Получаем количество оставшихся аудио remaining_count = voice_service.get_remaining_audio_count(message.from_user.id) - 1 await message.answer( text=f'Осталось непрослушанных: {remaining_count}', reply_markup=markup ) except Exception as e: logger.error(f"Ошибка при прослушивании аудио: {e}") await message.answer( text="Произошла ошибка при получении аудио. Попробуйте позже.", reply_markup=markup )