166 lines
6.4 KiB
Python
Executable File
166 lines
6.4 KiB
Python
Executable File
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"🤔 <b>Clei-Flow Precisa de Ajuda:</b>\nArquivo: <code>{filename}</code>",
|
|
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 |