📸 РАССЫЛКА С КАРТИНКАМИ
✅ Реализовано: - Рассылка текста (работает) - Рассылка картинки с подписью (НОВОЕ!) - Отправка в общий чат + в личку каждому - Отчёт админу об успешной рассылке 🎯 Как использовать: 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:
parent
d81ee6d238
commit
b4c06d09a3
1 changed files with 100 additions and 24 deletions
|
|
@ -32,6 +32,7 @@ router = Router()
|
||||||
|
|
||||||
class BroadcastState(StatesGroup):
|
class BroadcastState(StatesGroup):
|
||||||
waiting_for_message = State()
|
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):
|
async def cb_admin_broadcast(callback: CallbackQuery):
|
||||||
"""Рассылка сообщений"""
|
"""Рассылка сообщений"""
|
||||||
await callback.answer()
|
await callback.answer()
|
||||||
|
|
||||||
# Проверяем что это личка
|
# Проверяем что это личка
|
||||||
if callback.message.chat.type != 'private':
|
if callback.message.chat.type != 'private':
|
||||||
await callback.message.answer(
|
await callback.message.answer(
|
||||||
|
|
@ -305,14 +306,15 @@ async def cb_admin_broadcast(callback: CallbackQuery):
|
||||||
parse_mode='HTML'
|
parse_mode='HTML'
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
await callback.message.answer(
|
await callback.message.answer(
|
||||||
'📤 <b>Рассылка</b>\n\n'
|
'📤 <b>Рассылка</b>\n\n'
|
||||||
'Теперь отправьте сообщение, которое нужно разослать всем жильцам.\n\n'
|
'<b>Вариант 1:</b> Отправьте текст\n'
|
||||||
|
'<b>Вариант 2:</b> Отправьте картинку с подписью\n\n'
|
||||||
'Или отмените командой /cancel',
|
'Или отмените командой /cancel',
|
||||||
parse_mode='HTML'
|
parse_mode='HTML'
|
||||||
)
|
)
|
||||||
|
|
||||||
# Включаем состояние
|
# Включаем состояние
|
||||||
await callback.bot.set_state(callback.from_user.id, BroadcastState.waiting_for_message)
|
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))
|
@router.message(StateFilter(BroadcastState.waiting_for_message))
|
||||||
@admin_only
|
@admin_only
|
||||||
async def process_broadcast_message(message: Message):
|
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:
|
try:
|
||||||
await message.bot.send_message(
|
await bot.send_message(
|
||||||
config.ADMIN_CHAT_ID,
|
config.ADMIN_CHAT_ID,
|
||||||
f'📢 <b>Объявление от администрации</b>\n\n'
|
f'📢 <b>Объявление от администрации</b>\n\n'
|
||||||
f'{broadcast_text}',
|
f'{text}',
|
||||||
parse_mode='HTML'
|
parse_mode='HTML'
|
||||||
)
|
)
|
||||||
logger.info(f'Рассылка отправлена в чат {config.ADMIN_CHAT_ID}')
|
logger.info(f'Рассылка отправлена в чат {config.ADMIN_CHAT_ID}')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f'Ошибка отправки в чат: {e}')
|
logger.error(f'Ошибка отправки в чат: {e}')
|
||||||
|
|
||||||
# Рассылаем всем верифицированным в личку
|
# Рассылаем всем верифицированным в личку
|
||||||
async with AsyncSessionLocal() as session:
|
async with AsyncSessionLocal() as session:
|
||||||
stmt = select(User).where(User.verified == True)
|
stmt = select(User).where(User.verified == True)
|
||||||
result = await session.execute(stmt)
|
result = await session.execute(stmt)
|
||||||
users = list(result.scalars().all())
|
users = list(result.scalars().all())
|
||||||
|
|
||||||
success_count = 0
|
success_count = 0
|
||||||
error_count = 0
|
error_count = 0
|
||||||
|
|
||||||
for user in users:
|
for user in users:
|
||||||
try:
|
try:
|
||||||
await message.bot.send_message(
|
await bot.send_message(
|
||||||
user.user_id,
|
user.user_id,
|
||||||
f'📢 <b>Объявление от администрации</b>\n\n'
|
f'📢 <b>Объявление от администрации</b>\n\n'
|
||||||
f'{broadcast_text}',
|
f'{text}',
|
||||||
parse_mode='HTML'
|
parse_mode='HTML'
|
||||||
)
|
)
|
||||||
success_count += 1
|
success_count += 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f'Не удалось отправить пользователю {user.user_id}: {e}')
|
logger.error(f'Не удалось отправить пользователю {user.user_id}: {e}')
|
||||||
error_count += 1
|
error_count += 1
|
||||||
|
|
||||||
# Отчёт админу
|
# Отчёт админу
|
||||||
await message.answer(
|
await bot.send_message(
|
||||||
|
config.ADMIN_USER_ID,
|
||||||
f'✅ <b>Рассылка завершена!</b>\n\n'
|
f'✅ <b>Рассылка завершена!</b>\n\n'
|
||||||
f'Успешно: {success_count}\n'
|
f'Успешно: {success_count}\n'
|
||||||
f'Ошибок: {error_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'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# СНЯТИЕ ВЕРИФИКАЦИИ (БЫСТРОЕ)
|
# СНЯТИЕ ВЕРИФИКАЦИИ (БЫСТРОЕ)
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue