import asyncio
import httpx # Usamos para testar a rede antes
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import ApplicationBuilder, ContextTypes, CallbackQueryHandler, CommandHandler
from database import AppConfig
import logging
# Configuração de Log
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("telegram").setLevel(logging.INFO)
class TelegramManager:
def __init__(self):
# NÃO carregamos o token aqui. Carregamos na hora de iniciar.
self.app = None
self.active_requests = {}
self.is_connected = False
async def check_internet(self):
"""Testa se o container tem internet antes de tentar o Telegram"""
try:
async with httpx.AsyncClient(timeout=5.0) as client:
await client.get("https://www.google.com")
return True
except:
return False
async def start(self):
"""Inicia o Bot"""
# 1. Pega o Token Fresquinho do Banco
token = AppConfig.get_val('telegram_token')
chat_id = AppConfig.get_val('telegram_chat_id')
if not token:
print("🟡 Bot: Token não configurado. Aguardando você salvar no Painel...")
return
# 2. Teste de Rede Prévio
print("🤖 Bot: Verificando conectividade...")
if not await self.check_internet():
print("❌ Bot: ERRO DE REDE! O container não consegue acessar a internet.")
print(" -> Verifique DNS ou Firewall.")
return
print(f"🤖 Bot: Conectando com token termina em ...{token[-5:]}")
try:
# 3. Constroi a Aplicação
self.app = ApplicationBuilder().token(token).build()
# Handlers
self.app.add_handler(CommandHandler("start", self.cmd_start))
self.app.add_handler(CommandHandler("id", self.cmd_id))
self.app.add_handler(CallbackQueryHandler(self.handle_selection))
# Inicializa
await self.app.initialize()
await self.app.start()
# Inicia Polling (Limpa mensagens velhas acumuladas para não travar)
await self.app.updater.start_polling(drop_pending_updates=True)
self.is_connected = True
print("✅ Bot Online e Rodando!")
# Tenta mandar um oi se tiver chat_id
if chat_id:
try:
await self.app.bot.send_message(chat_id=chat_id, text="🚀 Clei-Flow: Conexão restabelecida!")
except Exception as e:
print(f"⚠️ Bot online, mas falhou ao enviar msg (Chat ID errado?): {e}")
except Exception as e:
print(f"❌ Falha Crítica no Bot: {e}")
self.is_connected = False
async def stop(self):
if self.app:
try:
await self.app.updater.stop()
await self.app.stop()
await self.app.shutdown()
self.is_connected = False
except: pass
# --- COMANDOS ---
async def cmd_start(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
chat_id = update.effective_chat.id
await update.message.reply_text(f"Olá! Configurado.\nSeu Chat ID é: `{chat_id}`", parse_mode='Markdown')
# Opcional: Salvar o Chat ID automaticamente se o usuário mandar /start
# AppConfig.set_val('telegram_chat_id', str(chat_id))
async def cmd_id(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text(f"`{update.effective_chat.id}`", parse_mode='Markdown')
# --- INTERAÇÃO (Renomeação) ---
async def ask_user_choice(self, filename, candidates):
chat_id = AppConfig.get_val('telegram_chat_id') # Pega sempre o atual
if not chat_id or not self.is_connected:
print("❌ Bot não pode perguntar (Sem Chat ID ou Desconectado)")
return None
request_id = f"req_{filename}"
keyboard = []
for cand in candidates:
# Texto do botão
text = f"{cand['title']} ({cand['year']})"
# Dados (ID|Tipo)
callback_data = f"{request_id}|{cand['tmdb_id']}|{cand['type']}"
keyboard.append([InlineKeyboardButton(text, callback_data=callback_data)])
keyboard.append([InlineKeyboardButton("🚫 Ignorar", callback_data=f"{request_id}|IGNORE|NONE")])
reply_markup = InlineKeyboardMarkup(keyboard)
try:
await self.app.bot.send_message(
chat_id=chat_id,
text=f"🤔 Clei-Flow Precisa de Ajuda:\nArquivo: {filename}",
reply_markup=reply_markup,
parse_mode='HTML'
)
except Exception as e:
print(f"Erro ao enviar pergunta: {e}")
return None
loop = asyncio.get_running_loop()
future = loop.create_future()
self.active_requests[request_id] = future
try:
# Espera 12 horas
result = await asyncio.wait_for(future, timeout=43200)
return result
except asyncio.TimeoutError:
if request_id in self.active_requests: del self.active_requests[request_id]
return None
async def handle_selection(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
await query.answer()
data = query.data.split('|')
if len(data) < 3: return
req_id = data[0]
tmdb_id = data[1]
media_type = data[2]
if req_id in self.active_requests:
future = self.active_requests[req_id]
if tmdb_id == 'IGNORE':
await query.edit_message_text(text=f"🚫 Ignorado.")
future.set_result(None)
else:
await query.edit_message_text(text=f"✅ Processando...")
future.set_result({'tmdb_id': int(tmdb_id), 'type': media_type})
del self.active_requests[req_id]
else:
await query.edit_message_text(text="⚠️ Solicitação expirada.")
async def send_notification(self, message):
chat_id = AppConfig.get_val('telegram_chat_id')
if self.app and chat_id and self.is_connected:
try:
await self.app.bot.send_message(chat_id=chat_id, text=message)
except: pass