Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from telethon import TelegramClient, events
- import asyncio
- import logging
- import os
- from pathlib import Path
- # Intentar cargar variables de entorno desde .env
- try:
- from dotenv import load_dotenv
- load_dotenv()
- logger_init = logging.getLogger(__name__)
- logger_init.info("✅ Variables de entorno cargadas desde .env")
- except ImportError:
- pass # python-dotenv no está instalado, usar valores directos
- # Configuración de logging
- logging.basicConfig(
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
- level=logging.INFO
- )
- logger = logging.getLogger(__name__)
- # ===================== CONFIGURACIÓN =====================
- # Opción 1: Usar variables de entorno (recomendado para seguridad)
- API_ID = os.getenv('API_ID') or 'TU_API_ID'
- API_HASH = os.getenv('API_HASH') or 'TU_API_HASH'
- BOT_TOKEN = os.getenv('BOT_TOKEN') or 'TU_BOT_TOKEN'
- SOURCE_CHANNEL = os.getenv('SOURCE_CHANNEL') or '@canal_origen'
- TARGET_CHANNEL = os.getenv('TARGET_CHANNEL') or '@canal_destino'
- # Extensiones de archivo a repostear (puedes agregar más)
- ALLOWED_EXTENSIONS = ('.zip', '.rar', '.7z', '.tar', '.gz', '.3mf', '.stl', '.gcode')
- # Opciones adicionales
- FORWARD_AS_COPY = False # Si True, copia el mensaje sin mostrar "Forwarded from"
- ADD_WATERMARK = False # Si True, agrega un texto al repostear
- WATERMARK_TEXT = "\n\n📦 Reposteado automáticamente"
- # =========================================================
- # Crear el cliente del bot
- bot = TelegramClient('bot_session', API_ID, API_HASH)
- def is_allowed_file(file_name):
- """
- Verifica si el archivo tiene una extensión permitida
- """
- if not file_name:
- return False
- return any(file_name.lower().endswith(ext) for ext in ALLOWED_EXTENSIONS)
- async def get_file_info(message):
- """
- Extrae información del archivo del mensaje
- """
- if not message.document:
- return None
- file_name = None
- file_size = message.document.size
- mime_type = message.document.mime_type
- for attribute in message.document.attributes:
- if hasattr(attribute, 'file_name'):
- file_name = attribute.file_name
- break
- return {
- 'name': file_name,
- 'size': file_size,
- 'mime_type': mime_type
- }
- def format_file_size(size_bytes):
- """
- Convierte bytes a formato legible (KB, MB, GB)
- """
- for unit in ['B', 'KB', 'MB', 'GB']:
- if size_bytes < 1024.0:
- return f"{size_bytes:.2f} {unit}"
- size_bytes /= 1024.0
- return f"{size_bytes:.2f} TB"
- @bot.on(events.NewMessage(chats=SOURCE_CHANNEL))
- async def repost_handler(event):
- """
- Maneja los nuevos mensajes del canal origen y los repostea al destino
- """
- try:
- message = event.message
- # Verificar si el mensaje tiene un archivo
- if message.media and message.document:
- file_info = await get_file_info(message)
- if not file_info or not file_info['name']:
- logger.debug("⏭️ Mensaje sin nombre de archivo, ignorado")
- return
- file_name = file_info['name']
- # Verificar si es una extensión permitida
- if is_allowed_file(file_name):
- file_size = format_file_size(file_info['size'])
- logger.info(f"📥 Reposteando archivo: {file_name} ({file_size})")
- if FORWARD_AS_COPY:
- # Opción: Enviar como copia (sin "Forwarded from")
- caption = message.message or ""
- if ADD_WATERMARK:
- caption += WATERMARK_TEXT
- await bot.send_file(
- TARGET_CHANNEL,
- file=message.media,
- caption=caption
- )
- else:
- # Opción: Forward directo (muestra "Forwarded from")
- await bot.forward_messages(
- entity=TARGET_CHANNEL,
- messages=message.id,
- from_peer=SOURCE_CHANNEL
- )
- logger.info(f"✅ Archivo reposteado exitosamente: {file_name}")
- else:
- logger.debug(f"⏭️ Archivo ignorado (extensión no permitida): {file_name}")
- else:
- logger.debug("⏭️ Mensaje sin archivo, ignorado")
- except Exception as e:
- logger.error(f"❌ Error al repostear mensaje: {e}", exc_info=True)
- @bot.on(events.NewMessage(pattern='/start'))
- async def start_handler(event):
- """
- Comando /start para verificar que el bot funciona
- """
- await event.respond(
- "🤖 **Bot de Reposteo Activo**\n\n"
- f"📡 Canal origen: `{SOURCE_CHANNEL}`\n"
- f"📤 Canal destino: `{TARGET_CHANNEL}`\n"
- f"📁 Extensiones: {', '.join(ALLOWED_EXTENSIONS)}\n\n"
- "✅ El bot está funcionando correctamente."
- )
- @bot.on(events.NewMessage(pattern='/status'))
- async def status_handler(event):
- """
- Comando /status para verificar el estado del bot
- """
- try:
- # Verificar acceso a los canales
- source_entity = await bot.get_entity(SOURCE_CHANNEL)
- target_entity = await bot.get_entity(TARGET_CHANNEL)
- await event.respond(
- "📊 **Estado del Bot**\n\n"
- f"✅ Canal origen: {source_entity.title}\n"
- f"✅ Canal destino: {target_entity.title}\n"
- f"✅ Extensiones activas: {len(ALLOWED_EXTENSIONS)}\n"
- f"✅ Bot funcionando correctamente"
- )
- except Exception as e:
- await event.respond(f"❌ Error: {e}")
- async def main():
- """
- Función principal para iniciar el bot
- """
- logger.info("🤖 Iniciando bot...")
- # Validar configuración
- if API_ID == 'TU_API_ID' or API_HASH == 'TU_API_HASH':
- logger.error("❌ ERROR: Debes configurar API_ID y API_HASH")
- return
- if BOT_TOKEN == 'TU_BOT_TOKEN':
- logger.error("❌ ERROR: Debes configurar BOT_TOKEN")
- return
- # Conectar con el token del bot
- await bot.start(bot_token=BOT_TOKEN)
- # Obtener información del bot
- me = await bot.get_me()
- logger.info(f"✅ Bot conectado: @{me.username}")
- logger.info(f"📡 Escuchando mensajes en: {SOURCE_CHANNEL}")
- logger.info(f"📤 Reposteando a: {TARGET_CHANNEL}")
- logger.info(f"📁 Extensiones permitidas: {', '.join(ALLOWED_EXTENSIONS)}")
- logger.info(f"🔄 Modo: {'Copia' if FORWARD_AS_COPY else 'Forward'}")
- logger.info("🟢 Bot funcionando. Presiona Ctrl+C para detener.")
- logger.info("💡 Tip: Envía /start o /status al bot para verificar su estado")
- # Mantener el bot corriendo
- await bot.run_until_disconnected()
- if __name__ == '__main__':
- try:
- asyncio.run(main())
- except KeyboardInterrupt:
- logger.info("\n🛑 Bot detenido por el usuario")
- except Exception as e:
- logger.error(f"❌ Error fatal: {e}", exc_info=True)
Advertisement