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