📸 РАССЫЛКА С КАРТИНКАМИ

 Реализовано:
- Рассылка текста (работает)
- Рассылка картинки с подписью (НОВОЕ!)
- Отправка в общий чат + в личку каждому
- Отчёт админу об успешной рассылке

🎯 Как использовать:
1. /admin → 📤 Рассылка
2. Отправить текст ИЛИ картинку с подписью
3. Бот разошлёт всем верифицированным:
   - В общий чат
   - В личку каждому

📝 Для срочного объявления:
1. Напиши боту в личку
2. /admin
3. 📤 Рассылка
4. Отправь картинку + текст
5. Готово!

💡 Важно:
- Рассылка только верифицированным
- Картинка сжимается Telegram
- Подпись до 1024 символов

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
Admin 2026-03-04 18:32:09 +00:00
parent d81ee6d238
commit b4c06d09a3

View file

@ -32,6 +32,7 @@ router = Router()
class BroadcastState(StatesGroup):
waiting_for_message = State()
waiting_for_photo = State() # Состояние для ожидания картинки
# =============================================================================
@ -296,7 +297,7 @@ async def cb_admin_export(callback: CallbackQuery):
async def cb_admin_broadcast(callback: CallbackQuery):
"""Рассылка сообщений"""
await callback.answer()
# Проверяем что это личка
if callback.message.chat.type != 'private':
await callback.message.answer(
@ -305,14 +306,15 @@ async def cb_admin_broadcast(callback: CallbackQuery):
parse_mode='HTML'
)
return
await callback.message.answer(
'📤 <b>Рассылка</b>\n\n'
'Теперь отправьте сообщение, которое нужно разослать всем жильцам.\n\n'
'<b>Вариант 1:</b> Отправьте текст\n'
'<b>Вариант 2:</b> Отправьте картинку с подписью\n\n'
'Или отмените командой /cancel',
parse_mode='HTML'
)
# Включаем состояние
await callback.bot.set_state(callback.from_user.id, BroadcastState.waiting_for_message)
@ -324,54 +326,81 @@ async def cb_admin_broadcast(callback: CallbackQuery):
@router.message(StateFilter(BroadcastState.waiting_for_message))
@admin_only
async def process_broadcast_message(message: Message):
"""Обработка сообщения для рассылки"""
broadcast_text = message.text
# Отключаем состояние
await message.bot.delete_state(message.from_user.id)
# Подтверждаем
await message.answer(
f'📤 <b>Начинаю рассылку...</b>\n\n'
f'Сообщение: {broadcast_text[:100]}...'
)
"""Обработка сообщения для рассылки (текст или фото)"""
# Проверяем что прислал админ
if message.photo:
# Это картинка с подписью
photo_id = message.photo[-1].file_id # Берём наибольшее качество
caption = message.caption or ''
# Отключаем состояние
await message.bot.delete_state(message.from_user.id)
# Подтверждаем
await message.answer(
f'📤 <b>Начинаю рассылку с картинкой...</b>\n\n'
f'Текст: {caption[:100]}...' if caption else 'Без текста'
)
# Рассылаем
await send_broadcast_with_photo(message.bot, photo_id, caption)
else:
# Это текст
broadcast_text = message.text or ''
# Отключаем состояние
await message.bot.delete_state(message.from_user.id)
# Подтверждаем
await message.answer(
f'📤 <b>Начинаю рассылку...</b>\n\n'
f'Сообщение: {broadcast_text[:100]}...'
)
# Рассылаем текст
await send_broadcast_text(message.bot, broadcast_text)
async def send_broadcast_text(bot, text: str):
"""Рассылка текста"""
# Отправляем в чат дома
try:
await message.bot.send_message(
await bot.send_message(
config.ADMIN_CHAT_ID,
f'📢 <b>Объявление от администрации</b>\n\n'
f'{broadcast_text}',
f'{text}',
parse_mode='HTML'
)
logger.info(f'Рассылка отправлена в чат {config.ADMIN_CHAT_ID}')
except Exception as e:
logger.error(f'Ошибка отправки в чат: {e}')
# Рассылаем всем верифицированным в личку
async with AsyncSessionLocal() as session:
stmt = select(User).where(User.verified == True)
result = await session.execute(stmt)
users = list(result.scalars().all())
success_count = 0
error_count = 0
for user in users:
try:
await message.bot.send_message(
await bot.send_message(
user.user_id,
f'📢 <b>Объявление от администрации</b>\n\n'
f'{broadcast_text}',
f'{text}',
parse_mode='HTML'
)
success_count += 1
except Exception as e:
logger.error(f'Не удалось отправить пользователю {user.user_id}: {e}')
error_count += 1
# Отчёт админу
await message.answer(
await bot.send_message(
config.ADMIN_USER_ID,
f'✅ <b>Рассылка завершена!</b>\n\n'
f'Успешно: {success_count}\n'
f'Ошибок: {error_count}\n'
@ -380,6 +409,53 @@ async def process_broadcast_message(message: Message):
)
async def send_broadcast_with_photo(bot, photo_id: str, caption: str):
"""Рассылка картинки с подписью"""
# Отправляем в чат дома
try:
await bot.send_photo(
config.ADMIN_CHAT_ID,
photo_id,
caption=f'📢 <b>Объявление от администрации</b>\n\n{caption}',
parse_mode='HTML'
)
logger.info(f'Рассылка с фото отправлена в чат {config.ADMIN_CHAT_ID}')
except Exception as e:
logger.error(f'Ошибка отправки фото в чат: {e}')
# Рассылаем всем верифицированным в личку
async with AsyncSessionLocal() as session:
stmt = select(User).where(User.verified == True)
result = await session.execute(stmt)
users = list(result.scalars().all())
success_count = 0
error_count = 0
for user in users:
try:
await bot.send_photo(
user.user_id,
photo_id,
caption=f'📢 <b>Объявление от администрации</b>\n\n{caption}',
parse_mode='HTML'
)
success_count += 1
except Exception as e:
logger.error(f'Не удалось отправить фото пользователю {user.user_id}: {e}')
error_count += 1
# Отчёт админу
await bot.send_message(
config.ADMIN_USER_ID,
f'✅ <b>Рассылка с фото завершена!</b>\n\n'
f'Успешно: {success_count}\n'
f'Ошибок: {error_count}\n'
f'В чат: ✅',
parse_mode='HTML'
)
# =============================================================================
# СНЯТИЕ ВЕРИФИКАЦИИ (БЫСТРОЕ)
# =============================================================================