Files
TG_autoposter/app/handlers/pyrogram_client.py
2025-12-18 05:55:32 +09:00

228 lines
8.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import logging
from typing import List, Optional, Dict
from pyrogram import Client
from pyrogram.types import Message, ChatMember
from pyrogram.errors import (
FloodWait, UserDeactivated, ChatAdminRequired,
PeerIdInvalid, ChannelInvalid, UserNotParticipant
)
from app.settings import Config
logger = logging.getLogger(__name__)
class PyrogramClientManager:
"""Менеджер для работы с Pyrogram клиентом"""
def __init__(self):
self.client: Optional[Client] = None
self.is_initialized = False
async def initialize(self) -> bool:
"""Инициализировать Pyrogram клиент"""
try:
if not Config.USE_PYROGRAM:
logger.warning("Pyrogram отключен в конфигурации")
return False
if not (Config.PYROGRAM_API_ID and Config.PYROGRAM_API_HASH):
logger.error("PYROGRAM_API_ID или PYROGRAM_API_HASH не установлены")
return False
self.client = Client(
name="tg_autoposter",
api_id=Config.PYROGRAM_API_ID,
api_hash=Config.PYROGRAM_API_HASH,
phone_number=Config.PYROGRAM_PHONE
)
await self.client.start()
self.is_initialized = True
me = await self.client.get_me()
logger.info(f"Pyrogram клиент инициализирован: {me.first_name}")
return True
except Exception as e:
logger.error(f"Ошибка при инициализации Pyrogram: {e}")
return False
async def shutdown(self):
"""Остановить Pyrogram клиент"""
if self.client and self.is_initialized:
try:
await self.client.stop()
self.is_initialized = False
logger.info("Pyrogram клиент остановлен")
except Exception as e:
logger.error(f"Ошибка при остановке Pyrogram: {e}")
async def send_message(self, chat_id: int, text: str,
parse_mode: str = "html",
disable_web_page_preview: bool = True) -> Optional[Message]:
"""Отправить сообщение в чат"""
if not self.is_initialized:
logger.error("Pyrogram клиент не инициализирован")
return None
try:
message = await self.client.send_message(
chat_id=chat_id,
text=text,
parse_mode=parse_mode,
disable_web_page_preview=disable_web_page_preview
)
logger.info(f"Сообщение отправлено в чат {chat_id} (клиент)")
return message
except FloodWait as e:
logger.warning(f"FloodWait: нужно ждать {e.value} секунд")
raise
except (ChatAdminRequired, UserNotParticipant):
logger.error(f"Клиент не администратор или не участник чата {chat_id}")
return None
except PeerIdInvalid:
logger.error(f"Неверный ID чата: {chat_id}")
return None
except Exception as e:
logger.error(f"Ошибка при отправке сообщения: {e}")
return None
async def get_chat_members(self, chat_id: int, limit: int = None) -> List[ChatMember]:
"""Получить список участников чата"""
if not self.is_initialized:
logger.error("Pyrogram клиент не инициализирован")
return []
try:
members = []
async for member in self.client.get_chat_members(chat_id):
members.append(member)
if limit and len(members) >= limit:
break
logger.info(f"Получено {len(members)} участников из чата {chat_id}")
return members
except (ChatAdminRequired, UserNotParticipant):
logger.error(f"Нет прав получить участников чата {chat_id}")
return []
except Exception as e:
logger.error(f"Ошибка при получении участников: {e}")
return []
async def get_chat_info(self, chat_id: int) -> Optional[Dict]:
"""Получить информацию о чате"""
if not self.is_initialized:
logger.error("Pyrogram клиент не инициализирован")
return None
try:
chat = await self.client.get_chat(chat_id)
return {
'id': chat.id,
'title': chat.title,
'description': getattr(chat, 'description', None),
'members_count': getattr(chat, 'members_count', None),
'is_supergroup': chat.is_supergroup,
'linked_chat': getattr(chat, 'linked_chat_id', None)
}
except Exception as e:
logger.error(f"Ошибка при получении информации о чате {chat_id}: {e}")
return None
async def join_chat(self, chat_link: str) -> Optional[int]:
"""Присоединиться к чату по ссылке"""
if not self.is_initialized:
logger.error("Pyrogram клиент не инициализирован")
return None
try:
chat = await self.client.join_chat(chat_link)
logger.info(f"Присоединился к чату: {chat.id}")
return chat.id
except Exception as e:
logger.error(f"Ошибка при присоединении к чату: {e}")
return None
async def leave_chat(self, chat_id: int) -> bool:
"""Покинуть чат"""
if not self.is_initialized:
logger.error("Pyrogram клиент не инициализирован")
return False
try:
await self.client.leave_chat(chat_id)
logger.info(f"Покинул чат: {chat_id}")
return True
except Exception as e:
logger.error(f"Ошибка при выходе из чата: {e}")
return False
async def edit_message(self, chat_id: int, message_id: int, text: str) -> Optional[Message]:
"""Отредактировать сообщение"""
if not self.is_initialized:
logger.error("Pyrogram клиент не инициализирован")
return None
try:
message = await self.client.edit_message_text(
chat_id=chat_id,
message_id=message_id,
text=text,
parse_mode="html"
)
logger.info(f"Сообщение отредактировано: {chat_id}/{message_id}")
return message
except Exception as e:
logger.error(f"Ошибка при редактировании сообщения: {e}")
return None
async def delete_message(self, chat_id: int, message_id: int) -> bool:
"""Удалить сообщение"""
if not self.is_initialized:
logger.error("Pyrogram клиент не инициализирован")
return False
try:
await self.client.delete_messages(chat_id, message_id)
logger.info(f"Сообщение удалено: {chat_id}/{message_id}")
return True
except Exception as e:
logger.error(f"Ошибка при удалении сообщения: {e}")
return False
async def search_messages(self, chat_id: int, query: str, limit: int = 100) -> List[Message]:
"""Искать сообщения в чате"""
if not self.is_initialized:
logger.error("Pyrogram клиент не инициализирован")
return []
try:
messages = []
async for message in self.client.search_messages(chat_id, query=query, limit=limit):
messages.append(message)
logger.info(f"Найдено {len(messages)} сообщений по запросу '{query}'")
return messages
except Exception as e:
logger.error(f"Ошибка при поиске сообщений: {e}")
return []
def is_connected(self) -> bool:
"""Проверить, подключен ли клиент"""
return self.is_initialized and self.client is not None
# Глобальный экземпляр менеджера
pyrogram_manager = PyrogramClientManager()