Skip to main content

Cliente Python para ToDus (mensajería cubana) — chat, grupos, archivos, stickers y más

Project description

📱 toDus-API

PyPI Python Tests Publish License

Cliente Python para ToDus — la plataforma de mensajería instantánea cubana. Soporta chat privado, grupos MUC Light, archivos, imágenes, videos, stickers, botones interactivos y más.

  • Versión: 1.5.0
  • Python: >= 3.11
  • Autor: ElJoker63
  • Licencia: MIT

📦 Instalación

pip install toDus-API

O directamente desde el repositorio:

pip install git+https://github.com/ElJoker63/toDus-API.git

Para desarrollo:

git clone https://github.com/ElJoker63/toDus-API.git
cd toDus-API
pip install -e ".[dev]"

🔐 Autenticación (¡Importante!)

ToDus no usa contraseñas elegidas por el usuario. El proceso de autenticación tiene dos pasos:

  1. Obtener un token largo (96 caracteres) mediante validación por SMS.
  2. Usar ese token para hacer login y obtener un JWT de sesión, que se usa para todas las comunicaciones.

El cliente ToDusClient2 guarda ese token largo en el atributo password (nombre histórico), pero en la práctica debes entenderlo como auth_token.

🔹 Flujo para primera vez (SMS)

from todus import ToDusClient2

client = ToDusClient2(phone_number="535xxxxxxx")  # sin password aún

# 1. Pedir código SMS
client.request_code()   # te llega un PIN de 6 dígitos

# 2. Validar el código
client.validate_code("123456")
# Ahora client.password contiene el token largo (96 caracteres)
# ¡Guárdalo en un lugar seguro para futuras sesiones!

# 3. Obtener el JWT de sesión
client.login()   # ahora client.logged == True

🔹 Si ya tienes el token largo (de una sesión anterior)

client = ToDusClient2(phone_number="535xxxxxxx", password="ese_token_largo_que_guardaste")
client.login()   # obtiene el JWT internamente

⚠️ Importante: Nunca pases un JWT directamente al constructor. El cliente se encarga de renovarlo automáticamente cuando expira. El parámetro password espera el token largo de 96 caracteres.


🚀 Uso Rápido

Enviar mensajes (privados y grupos automáticamente)

# Asumiendo que ya hiciste login
client.send_message("535yyyyyyy", "¡Hola mundo!")   # privado
client.send_message("mi-grupo-id", "Hola grupo!")   # grupo (auto-detectado)

Enviar imagen (con subida previa)

from todus import FileType

# 1. Subir la imagen
with open("foto.jpg", "rb") as f:
    image_data = f.read()
url = client.upload_file(image_data, FileType.PICTURE)

# 2. Enviar el mensaje con la imagen
client.send_image_message(
    "535yyyyyyy",
    url=url,
    file_name="foto.jpg",
    file_size=len(image_data),
    caption="Mi foto"
)

Actualizar tu Perfil

# Cambiar nombre a mostrar (alias) y biografía (description)
client.update_profile(
    alias="Mi Bot Genial",
    bio="¡Hola! Soy un bot escrito en Python.",
)

# Cambiar foto de perfil (requiere subirla primero)
with open("avatar.jpg", "rb") as f:
    avatar_url, thumb_url = client.upload_avatar_from_file("avatar.jpg")
    client.update_profile(picture_url=avatar_url, thumbnail_url=thumb_url)

# Cambiar el @username (todus_id)
# NOTA: el nombre de usuario no puede contener espacios ni el prefijo '@'
client.set_todus_id("MiNuevoUsername")

Escuchar mensajes entrantes

def on_message(msg):
    if msg.get("body"):
        print(f"{msg['from']}: {msg['body']}")

client.listen_messages(on_message)   # bucle infinito

🤖 Bot de Ejemplo

En la carpeta examples/ encontrarás un bot funcional con comandos:

Comando Respuesta
/startMensaje de bienvenida con lista de comandos
/infoInformación sobre la librería
/pingpong

Ejecútalo con:

export TODUS_PHONE=535xxxxxxx
export TODUS_AUTH_TOKEN=token_largo_de_96_caracteres
python examples/bot.py

📡 Tipos de Mensaje Soportados

La librería soporta los siguientes tipos de mensaje:

Tipo Método (ToDusClient2)
Textosend_message(to, body)
Imagensend_image_message(to, url, file_name, file_size, ...)
Videosend_video_message(to, url, video_id, file_name, ...)
Archivosend_file_message(to, url, file_type, ...)
Stickersend_sticker_message(to, sticker_id, ...)
Contactosend_contact_message(to, contact_id, ...)
Botonessend_button_message(to, text, buttons)
Ubicaciónsend_location_message(to, lat, lon, ...)
Eventosend_event_message(to, title, start, end, ...)
Editaredit_message(to, new_body, original_msg_id)
Eliminardelete_message(to, message_id)

Auto-detección de destino: si el to no es un número cubano (10 dígitos empezando por 53), se asume que es un group_id y el mensaje se envía al grupo automáticamente.


👥 Grupos MUC Light

# Unirse a un grupo
client.groups.join("mi-grupo-id")

# Enviar mensaje al grupo (auto-detectado)
client.send_message("mi-grupo-id", "Hola grupo!")

# Callback específico para mensajes de ese grupo
def on_group_msg(msg):
    print(f"{msg['sender_phone']}: {msg['body']}")

client.groups.on_group_message("mi-grupo-id", on_group_msg)

# Salir del grupo
client.groups.leave("mi-grupo-id")

# --- ADMINISTRACIÓN AVANZADA ---
# Obtener enlace de invitación
client.groups.get_invite_link("mi-grupo-id")

# Revocar y regenerar enlace
client.groups.revoke_invite_link("mi-grupo-id")

# Obtener lista de miembros
client.groups.get_members("mi-grupo-id")

# Cambiar rol (participant, moderator, owner) o expulsar (none)
client.groups.set_member_role("mi-grupo-id", "5350000000", "participant")
client.groups.kick_member("mi-grupo-id", "5350000000")

# Utilidades para extraer resultados de los eventos
def on_message(msg):
    raw = msg.get("raw", "")
    members = client.groups.parse_members_response(raw)
    if members:
        print("Miembros:", members)
        
    link = client.groups.parse_invite_link_response(raw)
    if link:
        print("Enlace de invitación:", link)
        
client.add_message_listener(on_message)

📢 Canales de ToDus

La versión 1.4.6 incluye soporte nativo completo para interactuar con canales de ToDus usando el protocolo XMPP interno.

# Obtener lista de mis canales suscritos o administrados
client.get_my_channels()

# Crear un nuevo canal
client.create_channel(
    name="Canal de Mi Bot",
    link="bot_canal_oficial",  # sin el @
    public=1,
    desc="Este es el canal oficial de mi bot",
    picture="url_de_la_foto_subida"
)

# Obtener información de un canal
client.get_channel_info("bot_canal_oficial")

# Publicar un mensaje en el canal
# Se requiere enviar la stanza XML completa de la publicación
channel_jid = "bot_canal_oficial@ch.todus.cu"
msg_xml = "<message><b>¡Hola a todos los suscriptores!</b></message>"
client.publish_to_channel(channel_jid, msg_xml)

# Obtener el historial de publicaciones (paginado)
client.get_channel_publications(channel_jid, limit=25)

# Suscribirse y desuscribirse
client.subscribe_channel("todus_oficial")
client.leave_channel("todus_oficial")

🌟 Estados e Historias (NUEVO)

La versión 1.4.7 añade soporte nativo para los Estados/Historias de ToDus.

# Ver tus seguidores
client.get_followers()

# Publicar un nuevo estado (diccionario JSON automático)
# ToDus usa JSON en base64 internamente, la API lo convierte por ti.
estado = {
    "text": "¡Hola desde la API de Python!",
    "bg_color": "#ff0000",
    "font": 1
}
client.publish_status(estado)

# Seguir y dejar de seguir los estados de otros usuarios
client.follow_user("5350000000")
client.unfollow_user("5350000000")

📤 Subir y Descargar Archivos

# Subir cualquier archivo
with open("documento.pdf", "rb") as f:
    url = client.upload_file(f.read(), FileType.FILE)

# Descargar a una carpeta
size, path = client.download_file_to_folder(url, "./descargas")
print(f"Descargado {size} bytes en {path}")

⚠️ Excepciones

Excepción Cuándo ocurre
AuthenticationErrorCredenciales inválidas o falta autenticación
TokenExpiredErrorEl token JWT expiró (el cliente lo renueva automáticamente si usas ToDusClient2)
ConnectionLostErrorSe perdió la conexión XMPP
UploadErrorError al subir/descargar archivo
GroupErrorError en operación de grupo
ParseErrorStanza malformada

🗂️ Estructura del Proyecto

toDus-API/
├── todus/                     # Paquete principal
│   ├── __init__.py            # Exports y versión
│   ├── client/                # Cliente XMPP/HTTP
│   │   ├── __init__.py        # ToDusClient y ToDusClient2
│   │   ├── base.py            # Conexión y transporte
│   │   ├── auth.py            # Autenticación SMS/JWT
│   │   ├── message.py         # Envío/recepción de mensajes
│   │   ├── file.py            # Subida/descarga de archivos
│   │   ├── profile.py         # Perfil de usuario
│   │   ├── status.py          # Estados e historias
│   │   └── channels.py        # Canales de ToDus
│   ├── stanzas/               # Generadores de stanzas XML
│   │   ├── __init__.py
│   │   ├── private.py         # Chat privado
│   │   ├── group.py           # Chat grupal
│   │   ├── channels.py        # Canales
│   │   ├── status.py          # Estados e historias
│   │   ├── presence.py        # Presencia XMPP
│   │   └── utils.py           # Utilidades de protocolo
│   ├── group.py               # Cliente de grupos MUC Light
│   ├── parser.py              # Parser incremental de stanzas
│   ├── stanza.py              # Re-exports unificados
│   ├── types.py               # Enums (FileType, ChatState, etc.)
│   ├── util.py                # Utilidades (JID, XML, JWT)
│   ├── constants.py           # Hosts, puertos, versiones
│   └── errors.py              # Excepciones personalizadas
├── tests/                     # Tests unitarios
│   ├── test_util.py
│   ├── test_types.py
│   └── test_stanzas.py
├── examples/                  # Ejemplos de uso
│   ├── bot.py
│   ├── send_grupo_admin.py
│   ├── update_profile.py
│   ├── status_example.py
│   └── channels_example.py
├── .github/workflows/         # CI/CD
│   ├── ci.yml                 # Tests en push/PR
│   └── pypi-publish.yml       # Publicación a PyPI
├── pyproject.toml             # Configuración del paquete
├── LICENSE                    # Licencia MIT
├── CHANGELOG.md               # Registro de cambios
├── CONTRIBUTING.md            # Guía para contribuir
├── MANIFEST.in                # Archivos incluidos en sdist
└── README.md                  # Este archivo

🔗 Recursos

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

todus_api-1.5.0.tar.gz (48.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

todus_api-1.5.0-py3-none-any.whl (47.8 kB view details)

Uploaded Python 3

File details

Details for the file todus_api-1.5.0.tar.gz.

File metadata

  • Download URL: todus_api-1.5.0.tar.gz
  • Upload date:
  • Size: 48.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for todus_api-1.5.0.tar.gz
Algorithm Hash digest
SHA256 751ac6e34ea4bb0fa5d482f217ece540e0669f23b6a77a7410c7f9523dfe3be8
MD5 91068ed21b46249df6b66cefb933172a
BLAKE2b-256 12b7eaf31092f3d8e58243feb8fed294cc285b9e6dc4ee07094e0e1488f68b7c

See more details on using hashes here.

File details

Details for the file todus_api-1.5.0-py3-none-any.whl.

File metadata

  • Download URL: todus_api-1.5.0-py3-none-any.whl
  • Upload date:
  • Size: 47.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for todus_api-1.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3f2dfee221764b74a92b5bd7743bf486b686c9f2ce2dbdc8ae5c65634b3473f0
MD5 91decaf2986346ac78e9de8c42cd1c47
BLAKE2b-256 091bb2946c68d69ab056ed17ec9f0dbfe8cd73712810ebc2971862adcbbf1403

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page